SurrealKit is published as a Rust crate, so you can drive connections, schema sync, rollouts, and seeding from application code rather than the CLI. This suits applications that apply schema inside their own process at startup, for example with an embedded SurrealDB backend (RocksDB, SpeeDB) or when running SurrealDB in the same binary during tests.
Adding the dependency
Sync vs rollout
SurrealKit gives you two ways to get schema into a database. Pick based on whether the database is disposable or shared.
| - | Sync | Rollout |
|---|---|---|
| Mental model | Declarative desired state: "make the database match this schema" | Staged, reviewable migration with an explicit undo |
| Applies | All changed files, idempotently | Ordered steps across start / complete / rollback phases |
| Removes objects | Automatically (prune) | Only in the complete phase, via explicit steps |
| Reversible | No | Yes (rollback) |
| Use when | Dev, test, CI, single-owner or embedded databases | Shared and production databases needing expand → contract and a rollback path |
The two work together: use sync for everyday schema, and use a rollout when a change needs to land safely while old and new code run side by side.
Connecting
DbCfg reads connection details from the same environment variables as the CLI (SURREALDB_HOST, SURREALDB_NAMESPACE, and so on), with optional overrides. connect builds the surrealdb::Surreal client and authenticates:
DbOverrides lets you override specific fields programmatically while leaving the rest to the environment:
In-process SurrealDB
For an embedded SurrealDB engine (mem://, rocksdb://, speedb://), construct a Surreal client directly and pass it to any library function:
Syncing schema
Use the [Sync] builder to apply a slice of schema files to the database. By default it prunes objects that are no longer present and stops on the first error (prune = true, fail_fast = true):
The builder methods customise behaviour before calling run:
Sync runs setup internally and reads nothing from the filesystem. To embed your .surql files at compile time instead of hand-writing the slice, use the embed_schema! macro.
EmbeddedSchemaFile: path vs sql
The two fields serve different purposes:
pathis a stable tracking key, not a path that must exist on disk. SurrealKit stores it in its metadata tables to identify the file, detect content changes, and prune files that disappear. Keep it stable across releases: renaming it makes SurrealKit treat the old key as deleted and the new one as added.sqlis the content that gets applied. Changingsqlwhile holdingpathconstant is exactly what triggers a re-apply on the next sync.
Rollouts
Rollouts are defined entirely in code, with no TOML or .surql files on disk required. Build a spec with [RolloutSpec::builder] and drive it with the [Rollout] facade.
Status lifecycle
completed and rolled_back are terminal. failed and the running_* states are stuck states from an interrupted run; recover them with [Rollout::abandon] (or the CLI repair command). Only one rollout may be in a non-terminal state at a time.
Lifecycle example
Step actions
Each [RolloutStep] carries exactly one action, built with a constructor, so invalid combinations cannot be represented:
| Constructor | What it does |
|---|---|
RolloutStep::apply_schema(id, phase, sql) | Apply inline DDL (OVERWRITE is injected; safe to retry) |
RolloutStep::run_sql(id, phase, sql) | Run data-mutation SQL (must be safe to re-run) |
RolloutStep::assert_sql(id, phase, sql, expect) | Assert a query's output equals expect |
RolloutStep::remove_entities(id, phase, entities) | REMOVE … IF EXISTS the given objects |
Entities are identified with EntityKey { kind: EntityKind, scope, name }, where EntityKind is an enum (Table, Field, Index, Module, and so on) rather than a string.
Recovering a stuck rollout
If a process dies mid-rollout, the rollout is left in a running_* or failed state and blocks new rollouts. Inspect the recorded state, then recover it:
Seeding
[seed] runs the .surql files in a project's seed/ directory (lexicographic order), applying template variables:
The second argument is the project folder (the directory containing seed/), matching the CLI's --folder / SURREALDB_FOLDER.
Template variables
${VAR} placeholders in schema, seed, or rollout SQL are substituted from a [TemplateVars] map before execution. Lookups are case-insensitive, and an undefined variable is an error naming the missing key and file. Pass them via Sync::vars(...), Rollout::vars(...), or the seed argument:
See Template variables for the full resolution rules.
Metadata tables
SurrealKit maintains two internal tables in your namespace and database, created automatically:
| Table | Purpose |
|---|---|
__entity | Tracks every schema object SurrealKit manages (content hash, tracking key) |
__rollout | Tracks rollout execution state (see the status lifecycle above) |
Next steps
Library usage example: full worked sync and rollout programs
embed_schema!macro: bake schema into the binary at compile timeType generation: generate JSON and TypeScript types from the live schema