smig — Automatic SurrealDB Migrations

2 min read Original article ↗

What is smig?

smig is a schema migration tool for SurrealDB. You define your database structure in TypeScript, and smig figures out what SurrealQL (SQL) to run to make your database match.

Think of it like this: instead of writing SurrealQL migrations by hand, you describe what your database should look like, and smig works out the steps to get there.

typescript

import { defineSchema, string, datetime, index } from 'smig';

const users = defineSchema({
  table: 'user',
  fields: {
    email: string().required(),
    name: string(),
    createdAt: datetime().default('time::now()'),
  },
  indexes: {
    email: index(['email']).unique(),
  },
});

Run bun smig migrate and this becomes:

surql

DEFINE TABLE user TYPE NORMAL SCHEMAFULL;
DEFINE FIELD email ON TABLE user TYPE string ASSERT $value != NONE;
DEFINE FIELD name ON TABLE user TYPE string;
DEFINE FIELD createdAt ON TABLE user TYPE datetime DEFAULT time::now();
DEFINE INDEX email ON TABLE user FIELDS email UNIQUE;

Why smig?

If you’re evaluating tools

smig is the only migration tool built specifically for SurrealDB 3. It understands SurrealDB’s unique features:

  • Graph relations — First-class support for SurrealDB’s relation tables
  • Vector indexes — HNSW and MTREE for AI/ML similarity search
  • Full-text search — Custom analyzers with tokenizers and filters
  • Multi-model — Tables, documents, and graphs in one schema

If you’re a developer

The API is designed to feel natural:

typescript

// Fields have chainable methods
email: string()
  .required()
  .assert('string::is_email($value)')
  .comment('Primary contact email')

// Indexes are just as readable
emailIndex: index(['email'])
  .unique()
  .comment('Unique constraint on email')

// Vector search is one line
embeddingIndex: index(['embedding'])
  .hnsw(1536)
  .dist('COSINE')

How it works

At its core, smig follows a simple, robust workflow:

  1. You write a schema file describing your tables, fields, indexes
  2. smig compares your schema to what’s in the database
  3. smig generates the SQL needed to sync them up
  4. You run bun smig migrate to apply the changes
  5. smig records the migration so it knows what’s been applied

What can you define?

smig covers nearly everything in SurrealDB 3:

WhatWhy you’d use it
TablesStore your data
FieldsDefine columns with types and validation
IndexesSpeed up queries, enforce uniqueness, vector search
EventsRun logic when data changes
RelationsConnect records in a graph
FunctionsReusable database logic
AnalyzersConfigure full-text search
AccessAuthentication methods
ParamsGlobal configuration values
SequencesAuto-incrementing numbers