Generate & run migrations

Schemic generates migrations by diffing your schema against a recorded snapshot. This guide is the loop you run as you evolve a schema: change code, generate, apply. For the model behind it, see the migration model.

Generate a migration

Edit your schema, then run schemic gen with a name describing the change. gen diffs the schema against the snapshot and, if anything changed, writes a <timestamp>_add_user_role.surql file with forward and rollback bodies. When nothing changed it tells you so and writes nothing:

shell
npx schemic gen add_user_role
✓ No schema changes — nothing to generate.

Commit the generated .surql files. They are the reviewable, version-controlled record of how your schema evolved.

Apply pending migrations

schemic migrate (alias up) applies every pending migration in order:

shell
npx schemic migrate
↑ 20260613090000_add_user_role
 
✓ Applied 1 migration.

To apply only some, pass a count or a target:

Shell
npx schemic migrate 1            # apply the next one
npx schemic migrate --to 20260613090000_add_user_role  # up to and including this tag

Check status

schemic status shows which migrations are applied and which are pending:

shell
npx schemic status
✓ applied 20260601000000_initial
· pending 20260613090000_add_user_role
 
2 migrations, 1 pending.

Add --json for machine-readable output. status also flags two drift conditions: a migration whose file changed after it was applied, and a migration recorded as applied whose file is now missing.

Roll back

schemic rollback (alias down) reverts applied migrations newest-first, running each migration’s ELSE (rollback) branch:

Shell
npx schemic rollback            # revert the most recent
npx schemic rollback 2          # revert the last two
npx schemic rollback --to 20260601000000_initial  # revert everything after this tag

Verify migrations reproduce the schema

schemic check replays your migrations in a throwaway engine and confirms the result matches your current schema. It is the guard for CI — it catches a migration history that has drifted from your source of truth:

Shell
npx schemic check

By default it spins up an ephemeral in-memory SurrealDB from your local surreal CLI, so it never touches your real database. Add --schema to check the schema specifically. See configuration for pointing the replay at a different engine.

Squash into a baseline

As migrations accumulate, collapse them into one fresh baseline:

Shell
npx schemic gen --baseline --force

This regenerates the whole schema from an empty snapshot as a single migration, replacing the existing files. Use it to tidy history before a release.

Seed data

Seeds live in database/seed/ — TypeScript files that each export default defineSeed(async (db, ctx) => { … }). db is the connected client; ctx.file(name) reads a supporting file (raw .surql, JSON, …) sitting next to the seed and returns it as a string, and ctx.dir is the seed’s directory. defineSeed types both db and ctx, so there are no extra type imports. schemic seed runs index.ts (or every seed in filename order if there is none); schemic seed <name> runs one; --all runs them all. A leading NN- prefix orders a seed but is not part of its name (01-users.ts is the seed users).

database/seed/01-users.ts TypeScript
import { defineSeed } from "@schemic/surrealdb";

export default defineSeed(async (db, ctx) => {
  await db.query(ctx.file("schema.surql")); // reads ./schema.surql next to the seed, as a string
});
Shell
npx schemic seed            # index.ts, or every seed
npx schemic seed users      # one named seed
npx schemic seed --all      # every seed, in filename order

Where to go next