@karots/migrate
v0.1.2
Published
Lightweight, database-agnostic TypeScript migration engine
Readme
@karots/migrate
A lightweight, database-agnostic TypeScript migration engine.
Install
npm install @karots/migrate pgQuick Start
1. Create a migration
npx migrate create add_users_tableThis generates migrations/20240601120000_add_users_table.ts:
import { defineMigration } from "@karots/migrate";
export default defineMigration({
name: "20240601120000_add_users_table",
up: async (db) => {
await db.query(`
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
)
`);
},
down: async (db) => {
await db.query("DROP TABLE users");
},
});2. Run migrations
import { Pool } from "pg";
import { PgAdapter, Migrator } from "@karots/migrate";
import path from "path";
const db = new PgAdapter(new Pool({ connectionString: process.env.DATABASE_URL }));
const migrator = new Migrator({
db,
migrationsDir: path.resolve(__dirname, "../migrations"),
});
await migrator.up();
await db.end();CLI Commands
| Command | Description |
|---|---|
| migrate create <name> | Generate a new migration file |
| migrate status | List migration files (filesystem only) |
| migrate help | Show help |
Set KAROTS_MIGRATIONS_DIR to override the default ./migrations directory.
Programmatic API
Migrator
const migrator = new Migrator({ db, migrationsDir });
await migrator.up(); // Apply all pending migrations
await migrator.down(); // Roll back the last applied migration
await migrator.status(); // Print full status table (DB-aware)Custom DB Adapter
Implement the DBClient interface to use any database:
import { DBClient } from "@karots/migrate";
class MyAdapter implements DBClient {
async query(sql: string, params?: unknown[]) {
// ...
return { rows: [] };
}
async transaction<T>(fn: (tx: DBClient) => Promise<T>) {
// begin / commit / rollback around fn(this)
}
}Safety Features
| Feature | Description |
|---|---|
| Hash protection | SHA-256 of each file stored after execution; modified files are rejected |
| Filename validation | migration.name must exactly match the filename |
| Transaction safety | Every migration runs inside a DB transaction; failures auto-rollback |
| Concurrency lock | Only one migrator process can run at a time |
| Deterministic order | Files sorted by timestamp-prefixed filename |
File Structure
src/
core/
types.ts ← DBClient interface, MigrationDefinition, helpers
hash.ts ← SHA-256 file hashing
validator.ts ← name/filename consistency, duplicate detection
loader.ts ← discover & require migration files
bootstrap.ts ← create migrations + lock tables
lock.ts ← acquire/release execution lock
migrator.ts ← main execution engine
adapters/
pg.ts ← PostgreSQL adapter (wraps pg.Pool)
cli/
index.ts ← CLI (generator + filesystem status only)
index.ts ← public package exports