TailorDB Commands

Commands for managing TailorDB tables, data, and schema migrations.

tailordb

Manage TailorDB tables and data.

Usage

tailor-sdk tailordb [command]

Commands

CommandDescription
tailordb erdGenerate ERD artifacts for TailorDB namespaces using Liam ERD. (beta)
tailordb migrationManage TailorDB schema migrations.
tailordb truncateTruncate (delete all records from) TailorDB tables.

tailordb truncate

Truncate (delete all records from) TailorDB tables.

Usage

tailor-sdk tailordb truncate [options] [types]

Arguments

ArgumentDescriptionRequired
typesType names to truncateNo

Options

OptionAliasDescriptionRequiredDefault
--workspace-id <WORKSPACE_ID>-wWorkspace IDNo-
--profile <PROFILE>-pWorkspace profileNo-
--config <CONFIG>-cPath to SDK config fileNo"tailor.config.ts"
--yes-ySkip confirmation promptsNofalse
--all-aTruncate all tables in all namespacesNofalse
--namespace <NAMESPACE>-nTruncate all tables in specified namespaceNo-

tailordb migration

Manage TailorDB schema migrations.

Usage

tailor-sdk tailordb migration [command]

Commands

CommandDescription
tailordb migration generateGenerate migration files by detecting schema differences between current local types and the previous migration snapshot.
tailordb migration setSet migration checkpoint to a specific number.
tailordb migration statusShow the current migration status for TailorDB namespaces, including applied and pending migrations.

tailordb migration generate

Generate migration files by detecting schema differences between current local types and the previous migration snapshot.

Usage

tailor-sdk tailordb migration generate [options]

Options

OptionAliasDescriptionRequiredDefault
--yes-ySkip confirmation promptsNofalse
--config <CONFIG>-cPath to SDK config fileNo"tailor.config.ts"
--name <NAME>-nOptional description for the migrationNo-
--init-Delete existing migrations and start freshNofalse

tailordb migration set

Set migration checkpoint to a specific number.

Usage

tailor-sdk tailordb migration set [options] <number>

Arguments

ArgumentDescriptionRequired
numberMigration number to set (e.g., 0001 or 1)Yes

Options

OptionAliasDescriptionRequiredDefault
--workspace-id <WORKSPACE_ID>-wWorkspace IDNo-
--profile <PROFILE>-pWorkspace profileNo-
--config <CONFIG>-cPath to SDK config fileNo"tailor.config.ts"
--yes-ySkip confirmation promptsNofalse
--namespace <NAMESPACE>-nTarget TailorDB namespace (required if multiple namespaces exist)No-

tailordb migration status

Show the current migration status for TailorDB namespaces, including applied and pending migrations.

Usage

tailor-sdk tailordb migration status [options]

Options

OptionAliasDescriptionRequiredDefault
--workspace-id <WORKSPACE_ID>-wWorkspace IDNo-
--profile <PROFILE>-pWorkspace profileNo-
--config <CONFIG>-cPath to SDK config fileNo"tailor.config.ts"
--namespace <NAMESPACE>-nTarget TailorDB namespace (shows all namespaces if not specified)No-

tailordb erd

Generate ERD artifacts for TailorDB namespaces using Liam ERD. (beta)

Usage

tailor-sdk tailordb erd [command]

Commands

CommandDescription
tailordb erd exportExport Liam ERD dist from applied TailorDB schema.
tailordb erd serveGenerate and serve ERD locally (liam build + serve dist). (beta)
tailordb erd deployDeploy ERD static website for TailorDB namespace(s).

tailordb erd export

Export Liam ERD dist from applied TailorDB schema.

Usage

tailor-sdk tailordb erd export [options]

Options

OptionAliasDescriptionRequiredDefault
--workspace-id <WORKSPACE_ID>-wWorkspace IDNo-
--profile <PROFILE>-pWorkspace profileNo-
--config <CONFIG>-cPath to SDK config fileNo"tailor.config.ts"
--json-jOutput as JSONNofalse
--namespace <NAMESPACE>-nTailorDB namespace name (optional if only one namespace is defined in config)No-
--output <OUTPUT>-oOutput directory path for tbls-compatible ERD JSON (writes to <outputDir>/<namespace>/schema.json)No".tailor-sdk/erd"

tailordb erd serve

Generate and serve ERD locally (liam build + serve dist). (beta)

Usage

tailor-sdk tailordb erd serve [options]

Options

OptionAliasDescriptionRequiredDefault
--workspace-id <WORKSPACE_ID>-wWorkspace IDNo-
--profile <PROFILE>-pWorkspace profileNo-
--config <CONFIG>-cPath to SDK config fileNo"tailor.config.ts"
--namespace <NAMESPACE>-nTailorDB namespace name (uses first namespace in config if not specified)No-

tailordb erd deploy

Deploy ERD static website for TailorDB namespace(s).

Usage

tailor-sdk tailordb erd deploy [options]

Options

OptionAliasDescriptionRequiredDefault
--workspace-id <WORKSPACE_ID>-wWorkspace IDNo-
--profile <PROFILE>-pWorkspace profileNo-
--config <CONFIG>-cPath to SDK config fileNo"tailor.config.ts"
--json-jOutput as JSONNofalse
--namespace <NAMESPACE>-nTailorDB namespace name (optional - deploys all namespaces with erdSite if omitted)No-

Usage Examples:

<span><span style="color: var(--shiki-token-comment)"># Truncate all tables in all namespaces (requires confirmation)</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">truncate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--all</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Truncate all tables in all namespaces (skip confirmation)</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">truncate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--all</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--yes</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Truncate all tables in a specific namespace</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">truncate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--namespace</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">myNamespace</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Truncate specific types (namespace is auto-detected)</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">truncate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">User</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">Post</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">Comment</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Truncate specific types with confirmation skipped</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">truncate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">User</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">Post</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--yes</span></span>
<span></span>

Notes:

  • You must specify exactly one of: --all, --namespace, or type names
  • When truncating specific types, the namespace is automatically detected from your config
  • Confirmation prompts vary based on the operation:
    • --all: requires typing truncate all
    • --namespace: requires typing truncate <namespace-name>
    • Specific types: requires typing yes
  • Use --yes flag to skip confirmation prompts (useful for scripts and CI/CD)

Overview

The migration system detects field-level schema differences between your local type definitions and the previous snapshot, then generates migration files to safely apply those changes with data transformations.

Key Features:

  • Local snapshot-based diff detection between current types and previous migration snapshot
  • Transaction-wrapped data migrations for atomicity - all changes commit or rollback together
  • Automatic execution during apply - pending migrations run as part of tailor-sdk apply
  • TypeScript migration scripts - type-safe data transformations using Kysely

Usage Examples:

<span><span style="color: var(--shiki-token-comment)"># Generate migration for all schema changes</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generate</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Generate with a description</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--name</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;add email field to user&quot;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Generate without confirmation prompts</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--yes</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Delete existing migrations and start fresh (with confirmation)</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--init</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Delete existing migrations and start fresh (skip confirmation)</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generate</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--init</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--yes</span></span>
<span></span>

Generated Files:

Each migration creates a directory in the migrations folder with a 4-digit sequential number:

FileDescription
0000/schema.jsonInitial schema snapshot (first migration only)
XXXX/diff.jsonSchema diff from previous snapshot
XXXX/migrate.tsData migration script (only when breaking changes)
XXXX/db.tsGenerated Kysely types for the migration script

Migration Script Structure:

<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">type</span><span style="color: var(--shiki-color-text)"> { Transaction } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;./db&quot;</span><span style="color: var(--shiki-color-text)">;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">async</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">function</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">main</span><span style="color: var(--shiki-color-text)">(trx</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Transaction</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Promise</span><span style="color: var(--shiki-color-text)">&lt;</span><span style="color: var(--shiki-token-constant)">void</span><span style="color: var(--shiki-color-text)">&gt; {</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-comment)">// Your data migration logic here</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-comment)">// All operations use the transaction object (trx)</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">await</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">trx</span><span style="color: var(--shiki-token-function)">.updateTable</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&quot;User&quot;</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-function)">.set</span><span style="color: var(--shiki-color-text)">({ newField</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;default value&quot;</span><span style="color: var(--shiki-color-text)"> })</span><span style="color: var(--shiki-token-function)">.execute</span><span style="color: var(--shiki-color-text)">();</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

The db.ts file contains Kysely Transaction types that reflect the schema state before the migration runs. This ensures type-safe data transformations based on the actual database structure at that point in time.

The main function receives a Kysely transaction object. All database operations should use this trx object to ensure atomicity - if any operation fails, all changes are rolled back.

Editor Integration:

If the EDITOR environment variable is set, the generated script file will automatically open in your preferred editor:

<span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> EDITOR</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string)">vim</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generate</span></span>
<span><span style="color: var(--shiki-token-comment)"># → After generation, vim opens XXXX/migrate.ts</span></span>
<span></span>

Usage Examples:

<span><span style="color: var(--shiki-token-comment)"># Set migration checkpoint to 0001 (with confirmation)</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">set</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Set migration checkpoint without confirmation</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">set</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--yes</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Set for specific namespace</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">set</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">2</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--namespace</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Reset to initial state (all migrations become pending)</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">set</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--yes</span></span>
<span></span>

Warning:

Setting the migration checkpoint changes which migrations will be executed on next apply:

  • Forward (e.g., 0001 → 0003): Skips migrations 0002 and 0003
  • Backward (e.g., 0003 → 0001): Migrations 0002 and 0003 become pending and will re-execute

The command always displays a warning and requires confirmation unless --yes is specified.

Usage Examples:

<span><span style="color: var(--shiki-token-comment)"># Show status for all namespaces</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">status</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Show status for specific namespace</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">status</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--namespace</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span></span>
<span></span>

Example Output:

Namespace: tailordb
  Current migration: 0001
  Pending migrations:
    - 0002: Add email field to user
    - 0003: Remove deprecated status field

Configuration

Configure migrations in tailor.config.ts:

<span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">default</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">defineConfig</span><span style="color: var(--shiki-color-text)">({</span></span>
<span><span style="color: var(--shiki-color-text)">  name</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;my-app&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  db</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    tailordb</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">      files</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> [</span><span style="color: var(--shiki-token-string-expression)">&quot;./tailordb/*.ts&quot;</span><span style="color: var(--shiki-color-text)">]</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">      migration</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">        directory</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;./migrations&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">        </span><span style="color: var(--shiki-token-comment)">// Optional: specify machine user for migration script execution</span></span>
<span><span style="color: var(--shiki-color-text)">        </span><span style="color: var(--shiki-token-comment)">// If not specified, the first machine user from auth.machineUsers is used</span></span>
<span><span style="color: var(--shiki-color-text)">        machineUser</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;admin-machine-user&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">      }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">});</span></span>
<span></span>

Configuration Options

OptionTypeDescription
filesstring[]Glob patterns for TailorDB type definition files
ignoresstring[]Glob patterns to ignore
migration.directorystringDirectory path for migration files
migration.machineUserstringMachine user name for migration script execution (optional, defaults to first machine user from auth.machineUsers)

Machine User Selection

When executing migration scripts, the system selects a machine user in the following priority:

  1. Explicit configuration: migration.machineUser in db config
  2. Auto-selection: First machine user from auth.machineUsers

The machine user being used is logged during migration execution.

Migration Directory Structure

Migrations use a directory-based structure with 4-digit sequential numbering:

migrations/
├── 0000/                    # Initial schema (number 0)
│   └── schema.json          # Full schema snapshot
├── 0001/                    # First change
│   ├── diff.json            # Schema diff
│   ├── migrate.ts           # Migration script (if breaking changes)
│   └── db.ts                # Kysely types (if breaking changes)
├── 0002/                    # Second change
│   └── diff.json
└── ...
  • 0000 - Initial schema snapshot (always starts at 0)
  • 0001 - First schema change
  • 0002 - Second schema change, etc.

Supported Schema Changes

Change TypeBreaking?Migration ScriptNotes
Add optional fieldNoNoSchema change only
Add required fieldYesYesScript populates default values
Remove fieldNoNoSchema change only - data is preserved
Change optional→requiredYesYesScript sets defaults for null values
Change required→optionalNoNoSchema change only
Add indexNoNoSchema change only
Remove indexNoNoSchema change only
Add unique constraintYesYesScript must resolve duplicate values
Remove unique constraintNoNoSchema change only
Add enum valueNoNoSchema change only
Remove enum valueYesYesScript migrates records with removed values
Add typeNoNoSchema change only
Remove typeNoNoSchema change only - data is preserved
Change field type--Not supported - requires 3-step migration
Change array to single value--Not supported - requires 3-step migration
Change single value to array--Not supported - requires 3-step migration
Change foreign key relationshipYesYesScript updates existing references

Unsupported Schema Changes

The following changes require a 3-step migration process:

Field Type Change

Field type changes (e.g., stringinteger) are not directly supported. Use this migration strategy:

  1. Migration 1: Add a new field with the desired type (e.g., fieldName_new) and migrate data
  2. Migration 2: Remove the old field
  3. Migration 3: Add the field with the original name and new type, migrate data from temporary field, then remove temporary field

Array Property Change

Changing between single value and array (e.g., array: falsearray: true) is not directly supported. Use the same 3-step migration strategy as field type changes.

Example Workflow

  1. Modify your type definition:

    <span><span style="color: var(--shiki-token-comment)">// tailordb/user.ts</span></span>
    <span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">user</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">db</span><span style="color: var(--shiki-token-function)">.type</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&quot;User&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> {</span></span>
    <span><span style="color: var(--shiki-color-text)">  name</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">db</span><span style="color: var(--shiki-token-function)">.string</span><span style="color: var(--shiki-color-text)">()</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
    <span><span style="color: var(--shiki-color-text)">  email</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">db</span><span style="color: var(--shiki-token-function)">.string</span><span style="color: var(--shiki-color-text)">()</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// ← New required field</span></span>
    <span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">...</span><span style="color: var(--shiki-token-constant)">db</span><span style="color: var(--shiki-token-function)">.</span><span style="color: var(--shiki-token-constant)">fields</span><span style="color: var(--shiki-token-function)">.timestamps</span><span style="color: var(--shiki-color-text)">()</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
    <span><span style="color: var(--shiki-color-text)">});</span></span>
    <span></span>
  2. Generate migration:

    <span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">migration</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generate</span></span>
    <span><span style="color: var(--shiki-token-comment)"># Output: Generated migration 0001</span></span>
    <span><span style="color: var(--shiki-token-comment)">#   Diff file: ./migrations/0001/diff.json</span></span>
    <span><span style="color: var(--shiki-token-comment)">#   Migration script: ./migrations/0001/migrate.ts</span></span>
    <span><span style="color: var(--shiki-token-comment)">#   DB types: ./migrations/0001/db.ts</span></span>
    <span></span>
  3. Edit the migration script (0001/migrate.ts):

    <span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">type</span><span style="color: var(--shiki-color-text)"> { Transaction } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;./db&quot;</span><span style="color: var(--shiki-color-text)">;</span></span>
    <span></span>
    <span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">async</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">function</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">main</span><span style="color: var(--shiki-color-text)">(trx</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Transaction</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Promise</span><span style="color: var(--shiki-color-text)">&lt;</span><span style="color: var(--shiki-token-constant)">void</span><span style="color: var(--shiki-color-text)">&gt; {</span></span>
    <span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">await</span><span style="color: var(--shiki-color-text)"> trx</span></span>
    <span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-function)">.updateTable</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&quot;User&quot;</span><span style="color: var(--shiki-color-text)">)</span></span>
    <span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-function)">.set</span><span style="color: var(--shiki-color-text)">({ email</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;default@example.com&quot;</span><span style="color: var(--shiki-color-text)"> })</span></span>
    <span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-function)">.where</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&quot;email&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;is&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">null</span><span style="color: var(--shiki-color-text)">)</span></span>
    <span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-function)">.execute</span><span style="color: var(--shiki-color-text)">();</span></span>
    <span><span style="color: var(--shiki-color-text)">}</span></span>
    <span></span>
  4. Apply migration:

    <span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">apply</span></span>
    <span><span style="color: var(--shiki-token-comment)"># Migrations are automatically executed during apply</span></span>
    <span></span>

Automatic Migration Execution

When running tailor-sdk apply, pending migration scripts are automatically executed as part of the deployment process.

How It Works

  1. Pending Migration Detection: Identifies migration scripts that haven't been executed yet
  2. Two-Stage Type Update: For breaking changes (required fields, type changes):
    • Pre-Migration: New fields are added as optional first
    • Script Execution: Migration scripts run to populate data
    • Post-Migration: Fields are changed to required, deletions are applied

Execution Flow

tailor-sdk apply
    │
    ├── Detect Pending Migrations
    │
    ├── [If pending migrations exist]
    │   ├── Pre-Migration: Add fields as optional
    │   ├── Execute Migration Scripts (TestExecScript API)
    │   └── Post-Migration: Apply required, deletions
    │
    └── Continue with normal apply flow

Requirements for Automatic Migration

  1. Migrations configured: migrations path set in db config
  2. Auth configured: Auth service with machine users
  3. Kysely generator: @tailor-platform/kysely-type generator configured

Schema Verification

By default, tailor-sdk apply performs two schema verifications:

  1. Local schema check: Ensures local type definitions match the migration snapshot
  2. Remote schema check: Ensures remote schema matches the expected state based on migration history

If remote schema drift is detected, you'll see an error like:

✖ Remote schema drift detected:
Namespace: tailordb
  Remote migration: 0007
  Differences:
  Type 'User':
    - Field 'email': required: remote=false, expected=true

ℹ This may indicate:
  - Another developer applied different migrations
  - Manual schema changes were made directly
  - Migration history is out of sync

ℹ Use '--no-schema-check' to skip this check (not recommended).

Skipping Schema Check

To skip both local and remote schema verification (not recommended for production):

<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">apply</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--no-schema-check</span></span>
<span></span>

Warning: Skipping schema checks may result in applying migrations to an inconsistent state.

Example Output

ℹ Found 2 pending migration(s) to execute.
ℹ Executing 2 pending migration(s)...
ℹ Using machine user: admin-machine-user

✔ Migration tailordb/0002 completed successfully
✔ Migration tailordb/0003 completed successfully

✔ All migrations completed successfully.
✔ Successfully applied changes.

Troubleshooting

Remote schema drift detected

Cause: The remote schema doesn't match the expected state based on migration history. This can happen when:

  • Another developer applied different migrations
  • Schema was changed manually outside of migrations
  • Migration history is out of sync

Solution:

  1. Check migration status: Run tailor-sdk tailordb migration status to see current state
  2. Sync with team: Ensure all team members have the same migration files
  3. Reset if needed: Use tailor-sdk tailordb migration set <number> to reset migration checkpoint
  4. Force apply (use with caution): Use --no-schema-check to skip verification

"Machine user not found"

Cause: Specified machine user doesn't exist in auth configuration.

Solution:

  1. Check available users: The error message lists available machine users
  2. Add machine user to your auth config:
    <span><span style="color: var(--shiki-color-text)">machineUsers</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
    <span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-string-expression)">&quot;your-user-name&quot;</span><span style="color: var(--shiki-color-text)">: {</span></span>
    <span><span style="color: var(--shiki-color-text)">    attributes</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> { role</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;ADMIN&quot;</span><span style="color: var(--shiki-color-text)"> }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
    <span><span style="color: var(--shiki-color-text)">  }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
    <span><span style="color: var(--shiki-color-text)">}</span></span>
    <span></span>
  3. Run tailor-sdk apply to deploy the auth config
  4. Retry migration

Migration script execution fails

Cause: Runtime error in your data migration logic.

Solution:

  1. Check the error message for the failing query/operation
  2. Test your script logic locally if possible
  3. Fix the script
  4. Apply again: tailor-sdk apply

Notes:

  • This command is a beta feature and may introduce breaking changes in future releases

Usage Examples:

<span><span style="color: var(--shiki-token-comment)"># Deploy ERD for all namespaces with erdSite configured</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">erd</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">deploy</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Deploy ERD for a specific namespace</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">erd</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">deploy</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--namespace</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">myNamespace</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># Deploy ERD with JSON output</span></span>
<span><span style="color: var(--shiki-token-function)">tailor-sdk</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tailordb</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">erd</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">deploy</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--json</span></span>
<span></span>

Notes:

  • Requires erdSite to be configured in tailor.config.ts for each namespace you want to deploy
  • Example config:
    <span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">default</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">defineConfig</span><span style="color: var(--shiki-color-text)">({</span></span>
    <span><span style="color: var(--shiki-color-text)">  db</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
    <span><span style="color: var(--shiki-color-text)">    myNamespace</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
    <span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-comment)">// ... table definitions</span></span>
    <span><span style="color: var(--shiki-color-text)">      erdSite</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;my-erd-site-name&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
    <span><span style="color: var(--shiki-color-text)">    }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
    <span><span style="color: var(--shiki-color-text)">  }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
    <span><span style="color: var(--shiki-color-text)">});</span></span>
    <span></span>