SlintORM
Docsnpm

Migrations

orm.migrate() reads your TypeScript interface files, generates a schema, diffs it against the current database, and applies the minimal set of DDL statements needed. No separate migration files to write.

orm.migrate()

// orm.migrate() — reads TypeScript source files,
// generates schema, diffs against current DB state, applies DDL

import ORMManager from 'slintorm';
const orm = new ORMManager({ driver: 'sqlite', databaseUrl: './dev.db', dir: './src' });

// Run once on startup or in a migration script
await orm.migrate();
// -> scans ./src for interface definitions
// -> generates schema/generated.ts + schema/generated.json
// -> creates/alters tables as needed

Auto-injected columns

// Columns injected automatically on every table:
// createdAt TEXT  — set on INSERT
// updatedAt TEXT  — set on INSERT and UPDATE

// deletedAt TEXT  — ONLY when a field has @softDelete
// (tables without @softDelete get no extra column)

Alter table (non-destructive)

// Alter table — non-destructive
// Adding a field to an interface adds the column
// Removing a field from an interface removes the column

// Before:
interface User {
  id: number;
  email: string;
  name: string;
}

// After (add bio, remove name):
interface User {
  id: number;
  email: string;
  // @nullable
  bio: string;
}

// migrate() runs:
// ALTER TABLE users ADD COLUMN bio TEXT
// ALTER TABLE users DROP COLUMN name  (Postgres/MySQL)
// On SQLite: recreate table (limitations apply)

_slint_migrations tracking table

SlintORM creates this table automatically. Each row records a migration batch, model name, and a SHA-256 hash. If the hash hasn't changed, that model's migration is skipped.

// _slint_migrations table — created automatically

-- SQLite / MySQL schema:
CREATE TABLE IF NOT EXISTS _slint_migrations (
  id        INTEGER PRIMARY KEY AUTOINCREMENT,
  name      TEXT NOT NULL,
  batch     INTEGER NOT NULL,
  hash      TEXT NOT NULL,
  snapshot  TEXT,
  migratedAt TEXT NOT NULL
);

-- Postgres schema:
CREATE TABLE IF NOT EXISTS _slint_migrations (
  id         SERIAL PRIMARY KEY,
  name       TEXT NOT NULL,
  batch      INTEGER NOT NULL,
  hash       TEXT NOT NULL,
  snapshot   TEXT,
  migratedAt TEXT NOT NULL
);

Migration hooks

// MigrationRunHooks — observe migration progress
await orm.migrate({
  onPending(units) {
    console.log(`${units.length} migrations pending`);
  },
  onProgress(unit) {
    console.log(`Running: ${unit.name}`);
  },
  onDone(result) {
    console.log(`Done. ${result.ran} migrations applied.`);
  },
  onError(unit, err) {
    console.error(`Failed: ${unit.name}`, err);
  },
});

Schema snapshots

// Schema snapshots
// Saved to: src/schema/migrations/_schema_snapshots/batch-N/
// Each batch captures a JSON snapshot of all model schemas at that point

// hashSchemaModel — SHA-256 of stable JSON
// If the hash matches the last recorded hash, no migration runs for that model
// Change an interface -> hash changes -> migration runs

MigrationUnit / MigrationRunResult types

// MigrationUnit — represents one pending migration
interface MigrationUnit {
  name: string;      // model/table name
  hash: string;      // SHA-256 of schema JSON
  sql: string[];     // DDL statements to execute
  batch: number;     // batch number
}

// MigrationRunResult — returned by orm.migrate()
interface MigrationRunResult {
  ran: number;       // number of migrations applied
  skipped: number;   // number skipped (hash matched)
  batch: number;     // batch number used
}
Snapshot-based architecture

The migration system records field snapshots (not step-based diffs). This means if you change an existing model field's type or constraints without running fresh, the change may be silently skipped if the hash still matches. Use npx slintorm fresh to reset and re-run all migrations in development.

PreviousRelationsNextCLI