{"id":11323,"library":"migrate","title":"Node Migrate","description":"Node Migrate is an abstract migration framework designed for Node.js applications, offering both a command-line interface (CLI) and a programmatic API for managing schema or data changes. As of its latest version, 2.1.0, it provides a flexible mechanism to create, apply, and rollback migrations, supporting various database types through custom logic within migration files. It distinguishes itself by providing a simple, generator-based approach to migration file creation, allowing users to define their own templates and compilers (like Babel or TypeScript) for modern JavaScript features. The package prioritizes flexibility, enabling developers to integrate it into diverse project setups. Its release cadence is not explicitly stated but appears to be stable with infrequent major updates, making it a reliable choice for established Node.js projects requiring robust migration management.","status":"maintenance","version":"2.1.0","language":"javascript","source_language":"en","source_url":"git://github.com/visionmedia/node-migrate","tags":["javascript","migrate","migrations","typescript"],"install":[{"cmd":"npm install migrate","lang":"bash","label":"npm"},{"cmd":"yarn add migrate","lang":"bash","label":"yarn"},{"cmd":"pnpm add migrate","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Optional dependency for compiling migration files written with newer ECMAScript features or TypeScript.","package":"babel-register","optional":true}],"imports":[{"note":"This package primarily uses CommonJS `require()` for programmatic use. Direct ES module `import` statements are not officially supported without a CJS-to-ESM wrapper or bundler due to its CommonJS-only module type.","wrong":"import migrate from 'migrate';","symbol":"migrate","correct":"const migrate = require('migrate');"},{"note":"The `load` method is the primary entry point for programmatic migration execution. It accepts an options object and a callback, or returns a Promise if not using a callback.","symbol":"migrate.load","correct":"migrate.load({ stateStore: '.migrate' }, function (err, set) { /* ... */ });"},{"note":"Migration files themselves are CommonJS modules and must export `up` and `down` functions. These functions can be asynchronous (returning a Promise) or take a `next` callback. Do not call `next()` if the function is `async`.","wrong":"module.up = function () { ... }","symbol":"Migration `up` and `down` functions","correct":"exports.up = function (next) { /* ... */ next(); }\nexports.down = async function () { /* ... */ }"}],"quickstart":{"code":"import migrate from 'migrate';\nimport { resolve } from 'path';\nimport { existsSync, mkdirSync, writeFileSync } from 'fs';\n\n// Mock database object shared across migrations.\n// In a real application, this would be your actual database client or ORM connection.\nconst mockGlobalDb: { users?: string[]; products?: string[]; } = {};\n\n// Paths for migrations and state store\nconst migrationsDir = resolve('./migrations_quickstart_simple');\nconst stateStorePath = resolve('./.migrate_quickstart_simple_state');\n\n// Ensure directories and state file exist\nif (!existsSync(migrationsDir)) mkdirSync(migrationsDir);\nif (!existsSync(stateStorePath)) {\n  writeFileSync(stateStorePath, JSON.stringify({ lastRun: null, migrations: [] }), 'utf8');\n}\n\n// Create mock migration files\nconst createUsersMigrationContent = `\n// This 'db' variable refers to 'mockGlobalDb' from the quickstart example.\n// In real migrations, you would typically import or pass your database client.\nexports.up = function (next) {\n  console.log('Running UP: Create Users');\n  // Simulate a database operation\n  module.parent.exports.mockGlobalDb.users = ['Alice', 'Bob'];\n  next();\n};\n\nexports.down = function (next) {\n  console.log('Running DOWN: Drop Users');\n  // Simulate rolling back a database operation\n  delete module.parent.exports.mockGlobalDb.users;\n  next();\n};\n`;\n\nconst addProductsMigrationContent = `\n// This 'db' variable refers to 'mockGlobalDb' from the quickstart example.\nexports.up = async function () { // Using async/await, no 'next' callback needed\n  console.log('Running UP: Add Products');\n  // Simulate a database operation\n  module.parent.exports.mockGlobalDb.products = ['Laptop', 'Mouse'];\n};\n\nexports.down = async function () {\n  console.log('Running DOWN: Remove Products');\n  // Simulate rolling back a database operation\n  delete module.parent.exports.mockGlobalDb.products;\n};\n`;\n\n// Write the migration files for the quickstart to execute\nconst ts1 = Date.now() - 10000;\nconst ts2 = Date.now();\nwriteFileSync(resolve(migrationsDir, `${ts1}-create-users.js`), createUsersMigrationContent, 'utf8');\nwriteFileSync(resolve(migrationsDir, `${ts2}-add-products.js`), addProductsMigrationContent, 'utf8');\n\n// Expose mockGlobalDb so migration files (which are 'require'd) can access it.\n// This is a quickstart hack; in a real app, you'd pass your DB client correctly.\nObject.assign(module.exports, { mockGlobalDb });\n\nconsole.log('Initializing migrations...');\nmigrate.load({\n  stateStore: stateStorePath,\n  migrationsDirectory: migrationsDir\n}, function (err, set) {\n  if (err) {\n    console.error('Failed to load migrations:', err);\n    process.exit(1);\n  }\n\n  console.log('Migrations loaded. Current status:');\n  set.migrations.forEach(m => console.log(`- ${m.title}: ${m.state}`));\n\n  set.up(function (err) {\n    if (err) {\n      console.error('Failed to run UP migrations:', err);\n      process.exit(1);\n    }\n    console.log('\\nAll UP migrations successfully executed!');\n    console.log('Current mock database state:', mockGlobalDb);\n\n    // To demonstrate rolling back, uncomment the following:\n    /*\n    console.log('\\nRunning DOWN to \"create-users\" migration...');\n    set.down('create-users', function(err) {\n      if (err) {\n        console.error('Failed to run DOWN migrations:', err);\n        process.exit(1);\n      }\n      console.log('Successfully rolled back to \"create-users\"!');\n      console.log('Current mock database state after partial DOWN:', mockGlobalDb);\n    });\n    */\n  });\n});","lang":"typescript","description":"This example demonstrates the programmatic API of `migrate`, loading migrations from a temporary directory and executing them against a mock database object, including handling both callback-based and async functions."},"warnings":[{"fix":"For `async` functions, simply `await` any promises and return implicitly. For callback functions, ensure `next()` is called exactly once.","message":"Migrations using `async` functions should *not* call the `next()` callback. Calling both will result in a `TypeError` (e.g., 'next is not a function') or other unexpected behavior, as `next()` is intended for traditional callback-based asynchronous operations.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Ensure `stateStore` points to a persistent, writable file path that can store the migration history between application restarts. Pre-create an empty file if `migrate` doesn't have permissions to create it.","message":"The `stateStore` option is critical for tracking migration history. Using an ephemeral state store (e.g., `/dev/null`), or one located in a non-persistent or unwritable directory, can lead to migrations running multiple times or being out of sync on subsequent runs.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always use `migrate create <name>` to generate new migration files to ensure correct timestamp prefixing. Avoid manual renaming of migration files after creation.","message":"Migration files are ordered strictly by their timestamp prefix. Manually renaming files or creating them without using the `migrate create` CLI command can lead to an incorrect migration order or `ENOENT` errors if files are not found.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use CommonJS `require()` syntax: `const migrate = require('migrate');`. If you must use ESM in your project, consider using a tool like `ts-node` or `babel-node` with appropriate configuration, or use a CJS-to-ESM wrapper.","message":"The `migrate` package is distributed as a CommonJS module. Attempting to use ES module `import` syntax (e.g., `import migrate from 'migrate'`) directly in a pure ESM Node.js environment without a bundler, custom loader, or transpilation will result in a `SyntaxError`.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure your `npm run` scripts or deployment pipeline always include the `--compiler` flag with the correct value for all `migrate` CLI commands that interact with migration files.","message":"When using custom compilers (e.g., Babel, TypeScript) for your migration files, the `--compiler` flag must be consistently applied to both the `migrate create` command (if the generator needs it) and the `migrate up`/`migrate down` commands. Inconsistent application will lead to execution failures.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Remove the `next()` call from any migration function declared with the `async` keyword.","cause":"An asynchronous (async) migration function attempted to call the `next()` callback, which is only expected by callback-based migration functions.","error":"TypeError: next is not a function"},{"fix":"Verify that the directory containing the `stateStore` path is writable by the process, or manually create an empty `.migrate` file before running migrations.","cause":"The `stateStore` file specified in the configuration (default `.migrate`) does not exist, and `migrate` was unable to create it due to insufficient permissions or an invalid path.","error":"Error: Migration failed: ... - [Error: ENOENT: no such file or directory, open '.migrate']"},{"fix":"Double-check the `migrationsDirectory` configuration. Ensure the migration file's name (specifically the title part, e.g., 'add-users') matches what you're trying to `up` or `down` to.","cause":"The migration specified by `<name>` was not found in the `migrationsDirectory`, or the `migrationsDirectory` option is pointing to an incorrect location.","error":"Error: Could not find migration: <name>"},{"fix":"Replace `import migrate from 'migrate';` with `const migrate = require('migrate');`.","cause":"Attempting to use an ES module `import` statement to load the `migrate` package in a Node.js project that is configured for CommonJS modules, or when `migrate` itself is a CJS module.","error":"SyntaxError: Cannot use import statement outside a module"}],"ecosystem":"npm"}