Skip to content

Repository files navigation

Do Migrate

PostgreSQL migration tool on Node.js.

Overview

This SQL migration tool is designed to facilitate seamless database schema evolution. It operates based on a directory containing migration scripts and a defined order of execution.

Migration Directory Structure

  1. Migration Files: Each migration consists of two files: {name}.do.sql for applying the migration and {name}.undo.sql for reverting it.
  2. Order File: An order file lists migration names in the sequence they should be applied. It also supports @baseline and @shrink directives.

Migration Execution Logic

  1. Applying New Migrations: When a new migration is added to the directory and listed in the order file, the tool executes the corresponding .do.sql file.
  2. Reverting Migrations: If a migration is removed from the order file (in the feature zone), the tool executes the stored .undo.sql and deletes the history row.
  3. Modifying Migrations: If a feature-zone migration is altered, the tool reverts from the end of the list to the change point, then reapplies.
  4. Baseline zone: Names listed before @baseline are matched by name only (hash changes do not trigger undo/redo).
  5. Shrink: Names listed under @shrink are deleted from schema_versions without running undo. Clear the @shrink section after a successful --exec.

SQL Migration History Table

Columns:

  • name
  • do_sql — executed migration
  • undo_sql — undo migration SQL
  • do_hash — SHA-256 of do SQL
  • undo_hash — SHA-256 of undo SQL
  • exec_date — execution date

Possible actions

  • skip — already applied
  • shrink — remove history row without undo (@shrink)
  • remove — run undo and delete history row
  • add — run do and insert history row
  • adopt — insert history row without running do (new baseline on a non-empty DB)
  • change — reserved (inspect emits remove+add instead)

Ordering and file structure

Example order file:

init_2026_03_06_120000
@baseline
feature_1
feature_2

@shrink
init
feature_old_1
feature_old_2

Example migrations dir:

init_2026_03_06_120000.do.sql
init_2026_03_06_120000.undo.sql
feature_1.do.sql
feature_1.undo.sql
feature_2.do.sql
feature_2.undo.sql
order

Baseline workflow

When the migration list grows too large, squash history into a new init snapshot:

npx do-migrate baseline
npx do-migrate --exec
# then remove the @shrink section from order (optional cleanup)

Or in one step:

npx do-migrate baseline --exec

This will:

  1. Dump the live schema with pg_dump (requires PostgreSQL client tools)
  2. Create init_{timestamp}.do.sql / .undo.sql
  3. Rewrite order to init_{timestamp} + @baseline and move previous migrations into @shrink
  4. With --exec: shrink old history rows and adopt the new init (no do on a live DB)

Fresh databases with the new order will add (execute) the baseline dump, then apply later features.

To undo a feature migration, remove it from the list after @baseline and do not put it in @shrink.

To drop a migration from history without undo (folded into baseline), list it under @shrink.

Install

npm install do-migrate

Or use Docker. The baseline command needs pg_dump available.

CLI usage

View action plan:

npx do-migrate [options]

Execute:

npx do-migrate --exec [options]

Create baseline snapshot:

npx do-migrate baseline [--name <name>] [--exec] [options]

Options:

  • --exec — Execute planned actions
  • --host <host> — Database hostname (default: "localhost", env: MIGRATOR_DB_HOST)
  • --port <port> — Database port (default: 5432, env: MIGRATOR_DB_PORT)
  • --user <username> — Database user (env: MIGRATOR_DB_USER)
  • --password <password> — Database password (env: MIGRATOR_DB_PASSWORD)
  • --database <name> — Database name (env: MIGRATOR_DB_DATABASE)
  • --schema-table <name> — Migrator sync table name (default: "schema_versions", env: MIGRATOR_TABLE_NAME)
  • --schema-name <name> — Database schema name (default: "public", env: MIGRATOR_DB_SCHEMA_NAME)
  • --path <path> — Path to migrations dir (env: MIGRATOR_FILES_PATH)
  • -V, --verbose — Show skipped migrations in output
  • -v, --version — Output the current version
  • -h, --help — Display help

Env variables:

  • MIGRATOR_DB_HOST — Database host (default: localhost)
  • MIGRATOR_DB_PORT — Database port (default: 5432)
  • MIGRATOR_DB_USER — Database user (default: postgres)
  • MIGRATOR_DB_PASSWORD — Database password (default empty)
  • MIGRATOR_DB_DATABASE — Database name (default: postgres)
  • MIGRATOR_DB_SCHEMA_NAME — Database schema name (default: public)
  • MIGRATOR_DB_SSL — SSL enable flag (true/false, default: false)
  • MIGRATOR_DB_SSL_CHECK — SSL rejectUnauthorized (true/false, default: false)
  • MIGRATOR_DB_SSL_CA — SSL CA (pem string)
  • MIGRATOR_FILES_PATH — Path to migration dir (default: ./migrations). Legacy alias: MITRATOR_FILES_PATH
  • MIGRATOR_ORDER_FILE — Order file name (default: order). Legacy alias: MITRATOR_ORDER_FILE
  • MIGRATOR_TABLE_NAME — Sync table name (default: schema_versions)

API usage

import Migrator, { Config } from 'do-migrate';

const migrator = new Migrator(config);

await migrator.inspect();
await migrator.migrate((action) => console.log(action));
await migrator.baseline(); // rewrite files; then migrate() to apply
await migrator.close();

Docker

Inspect:

docker run --rm -e MIGRATOR_DB_HOST=... -v ./migrations:/migrator/migrations nim579/do-migrate

Execute:

docker run --rm -e MIGRATOR_DB_HOST=... -v ./migrations:/migrator/migrations nim579/do-migrate --exec

Docker Compose:

services:
  migrator:
    image: nim579/do-migrate:2
    command: ["--exec"]
    environment:
      - MIGRATOR_DB_HOST
      - MIGRATOR_DB_PORT
      - MIGRATOR_DB_USER
      - MIGRATOR_DB_PASSWORD
      - MIGRATOR_DB_DATABASE
    volumes:
      - ./migrations:/migrator/migrations

About

PostgreSQL migration tool on Node.js

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages