Skip to main content
The @talosjs/migrations package is a database migration runner for Bun’s native SQL client. A migration is a class implementing IMigration with up and down methods, a timestamp-based version, and an optional dependency list. Migrations are registered with a decorator, sorted by version, and run inside a transaction. Applied versions are tracked in a database table so each one runs exactly once.

How migrations behave

Every migration carries a timestamp version (YYYYMMDDHHMMSSMMM), and the runner sorts by version before applying migrations in order. The up() method applies a change and down() reverses it, which keeps schema changes symmetric and reviewable. Each migration runs inside sql.begin(), so a failure rolls back the whole migration and stops the run. Applied versions are recorded in a tracking table (default migrations), and anything already applied is skipped on the next run. A migration can also declare other migrations as dependencies, and those run first regardless of timestamp. As with the rest of the framework, you register a migration class with a decorator and the runner resolves it from the container.

The IMigration contract

A migration is a class that satisfies IMigration from @talosjs/migrations:
export interface IMigration {
  up: (tx: TransactionSQL, sql: SQL) => Promise<void>;
  down: (tx: TransactionSQL, sql: SQL) => Promise<void>;
  getVersion: () => string;
  getDependencies: () => Promise<MigrationClassType[]> | MigrationClassType[];
}
MemberPurpose
up(tx, sql)Apply the schema change. Runs inside a transaction (tx); sql is the pooled client.
down(tx, sql)Reverse the schema change: drop exactly what up added.
getVersion()Return the timestamp version string; used for ordering and tracking.
getDependencies()Return the migration classes that must run before this one.

The tracking table

The runner records one row per applied version in a tracking table (default migrations, id VARCHAR(20) PRIMARY KEY), creating it if it is missing. Before running a migration, the runner checks the table for its id; if it is already there, the migration is skipped. Rolling a migration back deletes its row, so a later migration:up re-applies it.

Environment variables

VariableRequiredPurpose
DATABASE_URLYes (unless databaseUrl is passed in config)Postgres connection string used by the runner, e.g. postgres://user:pass@localhost:5432/mydb.
DATABASE_URL=postgres://user:pass@localhost:5432/mydb

Next steps