@talosjs/migrations component is a database migration runner for Bun’s native SQL client. Each 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 them 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.
How it works
You write a migration class that implementsIMigration and register it with @decorator.migration(). The up() runner loads every registered migration, sorts it by version, and applies each pending one inside a transaction, recording the version when it succeeds.
The
up() runner drives the lifecycle:
The tracking table stores one row per applied version. Before running a migration, the runner checks the table for its
id; if it’s already there, the migration is skipped. Passing --drop to the runner first drops and recreates the public schema. That is destructive, so reserve it for development.
Environment variables
Usage
A migration is a class implementingIMigration, registered with the decorator. up() applies the change and down() reverses it:
up(). It reads DATABASE_URL by default, or takes an explicit connection string and tracking table name:
Writing migrations that hold up
Makedown() the exact reverse of up(): drop precisely what up adds, since an asymmetric or irreversible down() is a bug. Once a migration has run on a shared database, never edit it. Add a new corrective migration instead of rewriting one that already ran.
Add indexes for foreign keys, WHERE and ORDER BY columns, and unique constraints in up(), then drop them in down() before the table or column they cover. Keep column types, nullability, and lengths in sync with the entity definition, so a non-nullable column is also NOT NULL in the migration. Reserve --drop for development; it wipes the whole schema and must never touch a shared or production database. When one change has to precede another regardless of timestamps, declare it in getDependencies().
CLI command
Scaffold a migration with the generator.talos migration:create writes a timestamped migration class under modules/<module>/src/migrations/, a matching test under modules/<module>/tests/migrations/, refreshes the migrations.ts barrel export, and creates the module’s bin/migration/up.ts and bin/migration/down.ts runners if they are missing.
The migration file name is derived from a timestamp version automatically, so there is no
--name option. Capture the schema change when you implement up() and down().
The generated class is a ready-to-fill stub:
talos migration:up:
Roll back applied migrations with
talos migration:down. Each rollback runs the migration’s down() in a transaction and removes its row from the migrations table, so a later migration:up re-applies it:
See migration:create, migration:up, and migration:down for the full command references.
Use with Claude and Codex
The generator ships a matchingmigration:create skill. It runs the scaffold, then guides your AI agent through completing the migration: implementing up() with the schema change, down() with the reverse, and the indexes your queries need. Initialize the skills once for your agent.
- Claude
- Codex
Prompt
migration:create, then implements up() to add the avatar column and down() to drop it.