#surrealdb #migration #manage #testing #seed

app surrealkit

Manage migrations, seeding and tests for your SurrealDB via CLI

7 releases

Uses new Rust 2024

new 0.3.2 Feb 17, 2026
0.3.1 Feb 17, 2026
0.2.0 Feb 5, 2026
0.1.8 Dec 6, 2025
0.1.6 Sep 19, 2025

#275 in Database interfaces

Custom license

99KB
3.5K SLoC

SurrealKit

Crates.io Documentation License

NOT FOR PRODUCTION USE | For SurrealDB v3

Manage SurrealDB migrations, seeding, and testing with ease. Inspired by Eloquent ORM's migration pattern.

Scope

This project is designed to manage SurrealDB migrations, seed, testing, and database management. It is not intended for production use and is specifically tailored for SurrealDB version 3.

If and when SurrealDB implements first-class tooling to manage migrations, seeding, and testing, SurrealKit will be deprecated in favour of the official SurrealDB tooling but intends to provide seamless transition.

Usage

Install via Cargo:

cargo install surrealkit

Or download a prebuilt binary from GitHub Releases (Linux, macOS Intel/Apple Silicon, Windows).

Initialise a new project:

surrealkit init

This creates a directory /database with the necessary scaffolding

The following ENV variables will be picked up for your .env file, SurrealKit assumes you're using SurrealDB as a Web Database.

  • PUBLIC_DATABASE_HOST
  • PUBLIC_DATABASE_NAME
  • PUBLIC_DATABASE_NAMESPACE
  • DATABASE_USERNAME
  • DATABASE_PASSWORD

A table (_migration) is generated and managed by SurrealKit on your configured database.

Team Workflow

SurrealKit now separates schema authoring, dev sync, and deploy migrations:

  1. Edit desired state in database/schema/*.surql
  2. Reconcile dev DB with auto-prune:
surrealkit sync
  1. Watch mode for local development:
surrealkit sync --watch
  1. Generate a git-reviewed migration diff and update snapshots:
surrealkit commit --name add_customer_indexes

Generated migrations are written to database/migrations/*.surql. Snapshots are tracked in:

  • database/.surrealkit/schema_snapshot.json
  • database/.surrealkit/catalog_snapshot.json

To guard CI against missing migration/snapshot updates:

surrealkit commit --dry-run

If prune is enabled against a shared DB, SurrealKit requires explicit override:

surrealkit sync --allow-shared-prune

Seeding

Seeding will automatically run when you apply migrations. If you would like to reapply migrations, please re-apply your migrations.

surrealkit seed

Testing Framework

Testing Example

surrealkit test

The runner executes declarative TOML suites from database/tests/suites/*.toml and supports:

  • SQL assertion tests (sql_expect)
  • Permission rule matrices (permissions_matrix)
  • Schema metadata assertions (schema_metadata)
  • Schema behavior assertions (schema_behavior)
  • HTTP API endpoint assertions (api_request)

By default, each suite runs in an isolated ephemeral namespace/database and fails CI on any test failure.

CLI Flags

surrealkit test supports:

  • --suite <glob>
  • --case <glob>
  • --tag <tag> (repeatable)
  • --fail-fast
  • --parallel <N>
  • --json-out <path>
  • --no-setup
  • --no-sync
  • --no-seed
  • --base-url <url>
  • --timeout-ms <ms>
  • --keep-db

Global Config

Global test settings live in database/tests/config.toml.

Example:

[defaults]
timeout_ms = 10000
base_url = "http://localhost:8000"

[actors.root]
kind = "root"

Optional env fallbacks:

  • SURREALKIT_TEST_BASE_URL
  • SURREALKIT_TEST_TIMEOUT_MS
  • PUBLIC_DATABASE_HOST (used as API base URL fallback when test-specific base URL is not set)

Example Suite

name = "security_smoke"
tags = ["smoke", "security"]

[[cases]]
name = "guest_cannot_create_order"
kind = "sql_expect"
actor = "guest"
sql = "CREATE order CONTENT { total: 10 };"
allow = false
error_contains = "permission"

[[cases]]
name = "orders_api_returns_200"
kind = "api_request"
actor = "root"
method = "GET"
path = "/api/orders"
expected_status = 200

[[cases.body_assertions]]
path = "0.id"
exists = true

Actor Example (Namespace / Database / Record / Token / Headers)

[actors.reader]
kind = "database"
namespace = "app"
database = "main"
username_env = "TEST_DB_READER_USER"
password_env = "TEST_DB_READER_PASS"

[actors.jwt_actor]
kind = "token"
token_env = "TEST_API_JWT"

[actors.custom_client]
kind = "headers"
headers = { "x-tenant-id" = "tenant_a" }

Permission Matrix Example

[[cases]]
name = "reader_permissions"
kind = "permissions_matrix"
actor = "reader"
table = "order"
record_id = "perm_test"

[[cases.rules]]
action = "select"
allow = true

[[cases.rules]]
action = "update"
allow = false
error_contains = "permission"

JSON Reports for CI

Generate machine-readable output:

surrealkit test --json-out database/tests/report.json

The command exits non-zero if any case fails.

Dependencies

~59–92MB
~1.5M SLoC