Umzug
repository·main·Indexed 25 days ago
https://github.com/sequelize/umzugA framework-agnostic and database-agnostic migration tool for Node.js designed to run and roll back tasks like database migrations. It supports various storage backends, provides a programmatic API for executing migrations via up() and down() methods, and includes a CLI for managing the migration lifecycle. Umzug is written in TypeScript and supports ECMAScript modules (ESM), raw SQL clients, and custom templates for migration creation.
What's inside umzug
- Umzug is a framework-agnostic migration tool for Node.js. It provides a clean, programmatic API for running and rolling back tasks (such as database migrations). It is database-agnostic, meaning it can be used with any database system, and supports multiple storage mechanisms for tracking migration state. It is written in TypeScript and provides built-in typings for IDE auto-completion and documentation.
Use Umzug with bundlers via codegen
mainWhen using a bundler (like
esbuild,webpack,parcel,bun, etc.) to package migrations for different environments, you cannot rely on Umzug's default filesystem globbing because the bundler may not include files discovered via runtime filesystem scans.To solve this, use a code generation (codegen) pattern:
- Use a script to glob migration files before bundling.
- Import those files into a 'barrel' file (a single object containing all migrations).
- Pass that barrel object directly to the
Umzugconstructor using themigrations.resolveoption (or by providing the object directly if the constructor supports it) so the bundler can statically analyze and include the migrations.
This technique works with any bundling library that supports standard JavaScript imports.
Configure Umzug Storages
mainStorages determine where migration metadata is persisted. Supported storages include:
- JSONStorage: Persists migrations in a JSON file (default:
umzug.json). - memoryStorage: In-memory storage, ideal for tests.
- SequelizeStorage: Uses a
SequelizeMetatable in a SQL database. - MongoDBStorage: Uses a
migrationscollection in MongoDB. - Custom Storage: Any object implementing the
UmzugStorageinterface.
import { Umzug, memoryStorage } from 'umzug' const umzug = new Umzug({ migrations: ..., storage: memoryStorage(), logger: console, })- JSONStorage: Persists migrations in a JSON file (default:
Define migrations via files or direct list
mainUmzug supports two ways to define migrations:
1. Migration Files
Files typically export
upanddownasync functions. They are loaded using aglobpattern in themigrationsconfiguration.2. Direct Migrations List
You can pass an array of migration objects directly to the
migrationskey. Each object must have anameandup/downfunctions.const umzug = new Umzug({ migrations: [ { name: '00-first-migration', async up({context}) { /* ... */ }, async down({context}) { /* ... */ }, } ], context: sequelize.getQueryInterface(), logger: console, })// Example of direct migration list const {Umzug} = require('umzug') const umzug = new Umzug({ migrations: [ { name: '00-first-migration', async up({context}) { /* ... */ }, async down({context}) { /* ... */ }, }, { name: '01-foo-bar-migration', async up({context}) { /* ... */ }, async down({context}) { /* ... */ }, }, ], context: sequelize.getQueryInterface(), logger: console, })Run migrations using the CLI with ts-node
mainYou can run migrations written in TypeScript by using a JavaScript entrypoint that registers
ts-node. This allows you to load TypeScript modules directly without a separate compilation step.Available CLI commands for the migration script:
node migrate --help: Show CLI helpnode migrate up: Apply migrationsnode migrate down: Revert the last migrationnode migrate down --to 0: Revert all migrationsnode migrate up --step 2: Run only two migrationsnode migrate create --name <name>.ts: Create a new migration file
node migrate --help # show CLI help node migrate up # apply migrations node migrate down # revert the last migration node migrate down --to 0 # revert all migrations node migrate up --step 2 # run only two migrations node migrate create --name new-migration.ts # create a new migration fileRun the Umzug bundling example
mainTo run the provided bundling example using
esbuild, follow these steps to install dependencies, generate the migration barrel, build the project, and execute migrations:# Install dependencies npm install # Update the migration barrel file npm run codegen # Build the project npm run build # Apply migrations node dist/umzug up # Create a new migration file node dist/umzug create --name new-migration.ts --skip-verify # Update the barrel again to include the new migration npm run codegennpm install npm run codegen npm run build node dist/umzug up node dist/umzug create --name new-migration.ts --skip-verify npm run codegenUse the Umzug CLI for migrations
mainThe Umzug CLI allows you to manage migrations directly from the command line. In a vanilla Node.js setup, you can use the following commands to control the migration lifecycle:
- Show help: View available CLI commands and flags.
- Apply migrations: Run all pending migrations.
- Revert migrations: Roll back the most recently applied migration.
- Create a migration: Generate a new migration file with a specific name.
- Revert all migrations: Roll back all applied migrations to the beginning (state 0).
node migrate --help # show CLI help node migrate up # apply migrations node migrate down # revert the last migration node migrate create --name new-migration.js # create a new migration file node migrate up # apply migrations again node migrate down --to 0 # revert all migrationsInstall Umzug via npm
mainYou can install Umzug using npm by specifying the correct tag:
npm install umzugUse ECMAScript modules (ESM) with Umzug
mainTo use ECMAScript modules with Umzug, you must provide a custom
migrations.resolvefunction in theUmzugconstructor. This function determines how migration files are loaded into the application.When implementing this:
- Use
import()to resolve.mjsmigration files. - Use
require()to resolve other formats (like.cjs). - Best Practice: Use explicit extensions like
.mjsor.cjsinstead of.jsto avoid ambiguity in how the files are resolved.
Depending on your environment and dependencies, you may or may not need to use
createRequireto facilitate the resolution of CommonJS files within an ESM context.- Use
Run Umzug migrations via CLI
mainIn this vanilla ESM setup, you can manage migrations using the
migrate.mjsscript via the Node.js CLI. The available commands allow you to view help, apply migrations, revert migrations, and generate new migration files.Commands:
node migrate.mjs --help: Display CLI help information.node migrate.mjs up: Apply pending migrations.node migrate.mjs down: Revert the most recent migration.node migrate.mjs down --to 0: Revert all applied migrations.node migrate.mjs create --name <filename>: Create a new migration file with the specified name.
node migrate.mjs --help # show CLI help node migrate.mjs up # apply migrations node migrate.mjs down # revert the last migration node migrate.mjs create --name new-migration.mjs # create a new migration file node migrate.mjs up # apply migrations again node migrate.mjs down --to 0 # revert all migrationsUse Umzug events for lifecycle hooks
mainUmzug emits events during the migration lifecycle that can be used to trigger side effects, such as shutting down internal services, logging, or notifying external systems. This allows you to hook into specific stages of the migration process (e.g., before or after migrations run).
node migrate upUse a custom template for migration creation
mainBy default, Umzug includes a basic template for creating new migrations. If you require a project-specific template (e.g., including specific imports, boilerplate, or file structures), you can implement a custom template resolver. This is typically achieved by reading a template file from a predefined folder on the filesystem during the migration creation process.
node migrate create --name new-migration.ts