Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
surrealkit: Rust library
This document covers SurrealKit as a Rust library. If you are looking for the CLI, see the project README.
The library is useful when you want schema management to happen inside your process at startup — for example with an embedded SurrealDB backend (RocksDB, SpeeDB) or when running SurrealDB in the same binary during tests.
Add to your project
[]
= "1.0.0-beta.1"
Cargo features
default = ["kv-mem", "cli"].
The cli feature builds the surrealkit binary and pulls in the dependencies
only it needs — clap, inquire, rustls (and its aws-lc-rs backend) and
tempfile. Library consumers can drop all of them:
[]
= { = "1.0.0-beta.1", = false, = ["kv-mem"] }
Storage engines: kv-mem (default), kv-surrealkv, kv-rocksdb, and embedded
for all three. Remote connections over HTTP need no feature.
You do not need these features to target an embedded engine from a library: cargo unifies features across the dependency graph, so enabling e.g.
surrealdb/kv-surrealkvin your own crate is enough for SurrealKit'sSurreal<Any>to opensurrealkv://.
Logging
SurrealKit emits progress (files applied, entities pruned, seeds executed)
through the log facade. Without a logger installed the
library is silent, which is the right default for a dependency.
To see progress, install any log implementation:
init;
Syncembedded.run.await?;
// INFO applied database/schema/person.surql
Records are emitted under the surrealkit target, so you can filter them:
RUST_LOG=surrealkit=info
Errors are still returned as Result; logging is for progress, not for failure
reporting.
Concepts: 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 DB 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/production databases where you need expand→contract and a rollback path |
The two compose: use sync for everyday schema and reach for a rollout when a change needs to land safely while old and new code run side-by-side.
Connecting
DbCfg reads connection details from environment variables (with optional overrides); connect builds the surrealdb::Surreal client and authenticates:
use ;
# async
Embedded databases
SurrealKit works against an in-process SurrealDB such as mem://, surrealkv://, or rocksdb://. Because Cargo unifies features across the dependency graph, you only need to enable the engine on your own surrealdb dependency. SurrealKit itself stays engine-agnostic:
[]
= "1.0.0-beta.1"
= { = "3", = ["kv-surrealkv"] }
connect detects embedded endpoints and skips authentication automatically (a fresh embedded datastore has no users), so the same DbCfg/connect flow works:
use ;
# async
Or construct a Surreal directly and pass it to any library function:
use connect;
use Config;
use Capabilities;
# async
Endpoints treated as embedded (no signin): mem://, surrealkv://, rocksdb://, speedb://, file://, tikv://, indxdb://. Pass --auth-level none (CLI) to force this for any endpoint.
Schema sync
embed_schema! (compile-time embedding)
embed_schema! walks your .surql files at build time and bakes them into the binary. The generated embedded_schema::sync applies any file whose content changed:
// Reads database/schema/**/*.surql relative to your Cargo.toml at compile time.
embed_schema!;
async
A custom path relative to your Cargo.toml may be passed: embed_schema!("my/schema/dir"). The generated module is always named embedded_schema.
Sync builder (runtime control)
To build the schema slice yourself, or to customize behavior, use the [Sync] builder:
use ;
use Any;
static SCHEMA: & = &;
# async
Sync calls setup internally and reads nothing from the filesystem — it never writes scaffolding files.
EmbeddedSchemaFile: path vs sql
This trips people up, so to be explicit:
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 — no TOML or .surql files on disk required. Build a spec with [RolloutSpec::builder] and drive it with the [Rollout] facade.
Status lifecycle
planned → running_start → ready_to_complete → running_complete → completed
│
└── running_rollback → rolled_back
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
use ;
use Any;
// The desired schema once the rollout completes (used to compute the managed
// catalog). Pass `&[]` if your steps fully describe the entity changes.
static TARGET: & = &;
# async
Step actions
Each [RolloutStep] carries exactly one action, built with a constructor — 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 |
Recovery / stuck rollouts
If a process dies mid-rollout, the rollout is left in a running_* or failed state and blocks new rollouts. To inspect and recover:
# use ;
# use Any;
# async
Seeding
Seeding is idempotent: each file is tracked in the __seed table by a content hash, so it runs only on first boot or when its sql changes. This makes it safe to call on every startup, so re-running a seed of fixed-id records no longer errors.
seed() runs .surql files from a seed/ directory (lexicographic order), applying template variables:
# use ;
# use Any;
# async
Embedded seeds (embed_seed! / Seed)
To ship seeds inside a production binary, with no filesystem at runtime, bake them in with embed_seed! (the counterpart to embed_schema!):
// Reads database/seed/**/*.surql relative to your Cargo.toml at compile time.
embed_seed!;
# async
For runtime control, use the [Seed] builder directly:
use ;
use Any;
static SEEDS: & = &;
# async
Like [EmbeddedSchemaFile], EmbeddedSeedFile::path is a stable tracking key (not a path that must exist on disk) and sql is the content. Changing sql while holding path constant re-runs the file.
Template variables
${VAR} placeholders in schema/seed/rollout SQL are substituted from a [TemplateVars] map before execution (lookups are case-insensitive; undefined variables are an error that names the missing key and file). Pass them via Sync::vars(...), Rollout::vars(...), or seed.
Metadata tables
SurrealKit maintains these internal tables in your namespace/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) |
__seed |
Tracks applied seed files by content hash so they run only once / on change |