db-migrate vs migrate
Managing Database Migrations in Node.js
db-migratemigrate

Managing Database Migrations in Node.js

db-migrate and migrate are both Node.js libraries designed to handle database schema changes and data migrations over time. db-migrate is a comprehensive, framework-agnostic tool that supports multiple database drivers (SQL and NoSQL) and offers a robust CLI for generating, running, and rolling back migrations. It is built for complex projects requiring strict version control and multi-environment management. migrate, on the other hand, is a lightweight, minimalist library that focuses on executing JavaScript migration files in order. It provides a simple programmatic API and a basic CLI, making it ideal for developers who prefer to build their own tooling around a simple execution engine without heavy configuration.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
db-migrate02,343118 kB1273 years agoMIT
migrate01,54443.3 kB233 years agoMIT

db-migrate vs migrate: Architecture, DX, and Control Compared

Both db-migrate and migrate solve the same core problem: keeping your database schema in sync with your code over time. However, they take very different approaches to get there. db-migrate acts as a full-featured framework with built-in drivers and a powerful CLI, while migrate is a lean library that gives you the execution engine and expects you to bring the rest. Let's look at how they handle real-world engineering scenarios.

πŸ› οΈ Setup and Configuration: Convention vs. Minimalism

db-migrate relies on a configuration file (usually database.json) to define environments, drivers, and connection details. It comes with a built-in CLI that reads this config to manage everything.

# db-migrate: Initialize a project
npx db-migrate init

# Creates a database.json file with sections for dev, test, prod
// db-migrate: database.json
{
  "dev": {
    "driver": "pg",
    "user": "dev_user",
    "database": "my_app_dev"
  }
}

migrate has no required config file format. You typically create a simple JS file to configure the storage mechanism (where migration state is saved) and the directory containing migration files.

// migrate: config.js
const { Store, Migrator } = require('migrate');
const fs = require('fs');

// Define your own storage logic (e.g., a JSON file or DB table)
const store = new Store({
  path: './migrations.json',
  fs: fs
});

const migrator = new Migrator({
  store: store,
  migrationsDirectory: './db/migrations'
});

πŸ“œ Creating Migrations: Scaffolding vs. Manual Files

db-migrate shines with its scaffolding CLI. It generates boilerplate code with up and down functions tailored to your specific database driver.

# db-migrate: Generate a new migration
npx db-migrate create add-users-table
// db-migrate: Generated file (e.g., 20231027123456-add-users-table.js)
exports.up = function(db) {
  return db.createTable('users', {
    id: { type: 'int', primaryKey: true, autoIncrement: true },
    email: { type: 'string', unique: true }
  });
};

exports.down = function(db) {
  return db.dropTable('users');
};

migrate does not generate files. You create a JS file manually in your migrations folder. The API is generic; you use your own database client (like pg or mysql2) inside the functions.

// migrate: Manual file (e.g., 001-add-users-table.js)
const db = require('./db-client'); // Your custom DB connection

exports.up = async function(next) {
  await db.query('CREATE TABLE users (id SERIAL PRIMARY KEY, email TEXT UNIQUE)');
  next();
};

exports.down = async function(next) {
  await db.query('DROP TABLE users');
  next();
};

πŸš€ Running Migrations: Built-in CLI vs. Programmatic Control

db-migrate provides a rich CLI for all operations. You can run, rollback, reset, and check status directly from the terminal.

# db-migrate: Run all pending migrations
npx db-migrate up

# db-migrate: Rollback the last migration
npx db-migrate down

# db-migrate: Reset database (down then up)
npx db-migrate reset

migrate includes a basic CLI, but its real strength is programmatic usage. You often write a custom script (e.g., npm run migrate) to run the migrator, giving you full control over error handling and logging.

// migrate: Custom run script (run.js)
const { Migrator } = require('migrate');
const config = require('./config');

async function run() {
  try {
    await config.migrator.up();
    console.log('Migrations completed successfully');
  } catch (err) {
    console.error('Migration failed:', err);
    process.exit(1);
  }
}

run();
# migrate: Execute via custom script
node run.js

πŸ”„ Rollbacks and State Management

db-migrate tracks state in a dedicated table within your database (e.g., migrations). It knows exactly which migrations ran and in what order, allowing reliable rollbacks using the down export in each file.

// db-migrate: Explicit down function required for rollback
exports.down = function(db) {
  // Must reverse the 'up' operation exactly
  return db.removeColumn('users', 'age');
};

migrate stores state wherever you tell it to (a JSON file, a DB table, etc.). Rollbacks are possible but rely entirely on you implementing the down logic correctly. The library simply executes the down function of the specific migration you target.

// migrate: Manual rollback execution
await config.migrator.down('001-add-users-table.js');

🌐 Database Support: Multi-Driver vs. Bring-Your-Own

db-migrate supports a wide range of databases out of the box (PostgreSQL, MySQL, SQLite, MongoDB, Redis, etc.) by using official driver plugins. You just install the driver package (e.g., db-migrate-pg) and update your config.

# db-migrate: Install PostgreSQL driver
npm install db-migrate-pg

migrate is database-agnostic because it doesn't talk to the database itself. You use whatever client library you prefer (pg, mongoose, knex) inside your migration files. This offers maximum flexibility but requires more setup code.

// migrate: Using any client library
const { Pool } = require('pg');
const pool = new Pool({ connectionString: process.env.DATABASE_URL });

exports.up = async function(next) {
  const client = await pool.connect();
  try {
    await client.query('CREATE TABLE ...');
  } finally {
    client.release();
  }
  next();
};

🀝 Similarities: Shared Ground

Despite their differences, both libraries share core concepts essential for safe database evolution.

1. Sequential Execution

Both ensure migrations run in a strict order based on filenames or timestamps, preventing race conditions where tables are created after data is inserted.

// Both enforce order: 001-create-users.js runs before 002-add-email.js

2. Up/Down Pattern

Both rely on the standard up (apply change) and down (revert change) function exports to manage schema evolution and rollbacks.

// Both use this pattern
exports.up = function(...) { ... };
exports.down = function(...) { ... };

3. Idempotency Expectations

While neither forces it, both expect developers to write migrations that can handle being run in a controlled environment, often requiring checks to avoid errors if a migration is accidentally run twice.

// Common practice in both
// CREATE TABLE IF NOT EXISTS users ... 

πŸ“Š Summary: Key Differences

Featuredb-migratemigrate
PhilosophyπŸ—οΈ Full Framework🧩 Lightweight Library
CLIβœ… Rich, built-in CLIβš™οΈ Basic CLI / Programmatic
DB DriversπŸ”Œ Built-in plugins (SQL/NoSQL)πŸ™Œ Bring your own client
ConfigπŸ“„ database.json standardπŸ’» Custom JS object
Scaffoldingβœ… Auto-generates files❌ Manual file creation
Best ForLarge teams, complex appsMicroservices, custom setups

πŸ’‘ The Big Picture

db-migrate is like a Swiss Army Knife πŸ‡¨πŸ‡­β€”it has every tool you might need built right in. It's perfect for enterprise applications where standardization, multi-db support, and a strong CLI are non-negotiable. If you want to hit the ground running with minimal custom code, this is your choice.

migrate is like a set of high-quality raw materials πŸ§±β€”it gives you the core engine to execute migrations but leaves the design of the house up to you. It's ideal for developers who already have a preferred database client, want to keep dependencies low, or need to embed migration logic into a custom deployment pipeline.

Final Thought: If you need a solution that "just works" with heavy lifting done for you, pick db-migrate. If you value simplicity and want to own every line of your migration runner, pick migrate.

How to Choose: db-migrate vs migrate

  • db-migrate:

    Choose db-migrate if you are working on a large-scale application that requires support for multiple database types (e.g., PostgreSQL, MySQL, MongoDB) or needs a robust, built-in CLI for managing complex migration lifecycles. It is the better fit for teams that need strict environment separation, automatic rollback capabilities, and a standardized workflow that works out of the box without custom scripting.

  • migrate:

    Choose migrate if you prefer a minimal dependency that simply runs JavaScript files in sequence and lets you handle the rest (like CLI tools or database connections) yourself. It is ideal for smaller projects, microservices, or teams that want full control over their migration runner and do not need the overhead of a heavy framework with built-in database drivers.

README for db-migrate

Backers on Open Collective Sponsors on Open Collective Build Status Dependency Status devDependency Status Documentation Status Code Quality: Javascript Total Alerts

db-migrate

Join the chat at https://gitter.im/db-migrate/node-db-migrate

NPM

Database migration framework for node.js

Platinum sponsors

Details about sponsorships

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor] or reach out to magic+dbsponsorship@wizardtales.com.

Usage

Installation

$ npm install -g db-migrate

DB-Migrate is now available to you via:

$ db-migrate

As local module

Want to use db-migrate as local module?

$ npm install db-migrate

DB-Migrate is now available to you via:

$ node node_modules/db-migrate/bin/db-migrate

Officially Supported Databases

Resources and usage instructions

Please follow the link below, for usage instructions examples and the full documentation of db-migrate.

Documentation: https://db-migrate.readthedocs.io/en/latest/

Support db-migrate

Backers

A big thank you to our backers. You're a tremendous and important help, to keep the project healthy! [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor] or reach out to magic+dbsponsorship@wizardtales.com.

License

(The MIT License)

Copyright (c) 2015 Tobias Gurtzick

Copyright (c) 2013 Jeff Kunkle

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.