Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
U

umzug

> 编程语言
Open source

Framework agnostic migration tool for Node.js

2.2K stars0 likes0 views
WebsiteGitHub

About

Framework agnostic migration tool for Node.js

Umzug

Umzug is a framework-agnostic migration tool for Node. It provides a clean API for running and rolling back tasks.

Highlights

  • Written in TypeScript
    • Built-in typings
    • Auto-completion right in your IDE
    • Documentation right in your IDE
  • Programmatic API for migrations
  • Built-in CLI
  • Database agnostic
  • Supports logging of migration process
  • Supports multiple storages for migration data
  • Usage examples

Documentation

Note: these are the docs for the latest version of umzug, which has several breaking changes from v2.x. See the upgrading section for a migration guide. For the previous stable version, please refer to the v2.x branch.

Minimal Example

The following example uses a Sqlite database through sequelize and persists the migration data in the database itself through the sequelize storage. There are several more involved examples covering a few different scenarios in the examples folder. Note that although this uses Sequelize, Umzug isn't coupled to Sequelize, it's just one of the (most commonly-used) supported storages.

…
…

Note that we renamed the context argument to queryInterface for clarity. The context is whatever we specified when creating the Umzug instance in index.js.

You can also write your migrations in typescript by using `ts-node` in the entrypoint:
…
typescript
// migrations/00_initial.ts
import type { Migration } from '..';

// types will now be available for `queryInterface`
export const up: Migration = ({ context: queryInterface }) => queryInterface.createTable(...)
export const down: Migration = ({ context: queryInterface }) => queryInterface.dropTable(...)

See these tests for more examples of Umzug usage, including:

  • passing ignore and cwd parameters to the glob instructions
  • customising migrations ordering
  • finding migrations from multiple different directories
  • using non-js file extensions via a custom resolver, e.g. .sql

Usage

Installation

Umzug is available on npm by specifying the correct tag:

bash
npm install umzug

Umzug instance

It is possible to configure an Umzug instance by passing an object to the constructor.

javascript
const {Umzug} = require('umzug')

const umzug = new Umzug({
  /* ... options ... */
})

Detailed documentation for these options are in the UmzugOptions TypeScript interface, which can be found in src/types.ts.

Getting all pending migrations

You can get a list of pending (i.e. not yet executed) migrations with the pending() method:

javascript
const migrations = await umzug.pending()
// returns an array of all pending migrations.

Getting all executed migrations

You can get a list of already executed migrations with the executed() method:

javascript
const migrations = await umzug.executed()
// returns an array of all already executed migrations

Executing pending migrations

The up method can be used to execute all pending migrations.

javascript
const migrations = await umzug.up()
// returns an array of all executed migrations

It is also possible to pass the name of a migration in order to just run the migrations from the current state to the passed migration name (inclusive).

javascript
await umzug.up({to: '20141101203500-task'})

To limit the number of migrations that are run, step can be used:

javascript
// This will run the next two migrations
await umzug.up({step: 2})

Running specific migrations while ignoring the right order, can be done like this:

javascript
await umzug.up({migrations: ['20141101203500-task', '20141101203501-task-2']})

Reverting executed migration

The down method can be used to revert the last executed migration.

javascript
const migration = await umzug.down()
// reverts the last migration and returns it.

To revert more than one migration, you can use step:

javascript
// This will revert the last two migrations
await umzug.down({step: 2})

It is possible to pass the name of a migration until which (inclusive) the migrations should be reverted. This allows the reverting of multiple migrations at once.

javascript
const migrations = await umzug.down({to: '20141031080000-task'})
// returns an array of all reverted migrations.

To revert all migrations, you can pass 0 as the to parameter:

javascript
await umzug.down({to: 0})

Reverting specific migrations while ignoring the right order, can be done like this:

javascript
await umzug.down({migrations: ['20141101203500-task', '20141101203501-task-2']})

Migrations

There are two ways to specify migrations: via files or directly via an array of migrations.

Migration files

A migration file ideally exposes an up and a down async functions. They will perform the task of upgrading or downgrading the database.

javascript
module.exports = {
  async up() {
    /* ... */
  },
  async down() {
    /* ... */
  },
}

Migration files can be located anywhere - they will typically be loaded according to a glob pattern provided to the Umzug constructor.

Direct migrations list

You can also specify directly a list of migrations to the Umzug constructor:

javascript
const {Umzug} = require('umzug')

const umzug = new Umzug({
  migrations: [
    {
      // the name of the migration is mandatory
      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,
})

Modifying the parameters passed to your migration methods

Sometimes it's necessary to modify the parameters umzug will pass to your migration methods when the library calls the up and down methods for each migration. This is the case when using migrations currently generated using sequelize-cli. In this case you can use the resolve fuction during migration configuration to determine which parameters will be passed to the relevant method

…

Additional migration configuration options

To load migrations in another format, you can use the resolve function:

…

You can support mixed migration file types, and use umzug's default resolver for javascript/typescript:

…

The glob syntax allows loading migrations from multiple locations:

javascript
const {Sequelize} = require('sequelize')
const {Umzug} = require('umzug')

const umzug = new Umzug({
  migrations: {
    glob: '{first-folder/*.js,second-folder-with-different-naming-convention/*.js}',
  },
  context: new Sequelize(/* ... */),
  logger: console,
})

Note on migration file sorting:

  • file matches, found using tinyglobby, will be lexicographically sorted based on their paths
    • so if your migrations are one/m1.js, two/m2.js, three/m3.js, the resultant order will be one/m1.js, three/m3.js, two/m2.js
    • similarly, if your migrations are called m1.js, m2.js, ... m10.js, m11.js, the resultant ordering will be m1.js, m10.js, m11.js, ... m2.js
  • The easiest way to deal with this is to ensure your migrations appear in a single folder, and their paths match lexicographically with the order they should run in
  • If this isn't possible, the ordering can be customised using a new instance (previously, in the beta release for v3, this could be done with .extend(...) - see below for example using a new instance)

Upgrading from v2.x

The Umzug class should be imported as a named import, i.e. import { Umzug } from 'umzug'.

The MigrationMeta type, which is returned by umzug.executed() and umzug.pending(), no longer has a file property - it has a name and optional path - since migrations are not necessarily bound to files on the file system.

The migrations.glob parameter replaces path, pattern and traverseDirectories. It can be used, in combination with cwd and ignore to do much more flexible file lookups. See https://npmjs.com/package/tinyglobby for more information on the syntax.

The migrations.resolve parameter replaces customResolver. Explicit support for wrap and nameFormatter has been removed - these can be easily implemented in a resolve function.

The constructor option logging is replaced by logger to allow for warn and error messages in future. NodeJS's global console object can be passed to this. To disable logging, replace logging: false with logger: undefined.

Events have moved from the default nodejs EventEmitter to emittery. It has better design for async code, a less bloated API surface and strong types. But, it doesn't allow passing multiple arguments to callbacks, so listeners have to change slightly, as well as .addListener(...) and .removeListener(...) no longer being supported (.on(...) and .off(...) should now be used):

Before:

javascript
umzug.on('migrating', (name, m) => console.log({name, path: m.path}))

After:

javascript
umzug.on('migrating', ev => console.log({name: ev.name, path: ev.path}))

The Umzug#execute method is removed. Use Umzug#up or Umzug#down.

The options for Umguz#up and Umzug#down have changed:

  • umzug.up({ to: 'some-name' }) and umzug.down({ to: 'some-name' }) are still valid.
  • umzug.up({ from: '...' }) and umzug.down({ from: '...' }) are no longer supported. To run migrations out-of-order (which is not generally recommended), you can explicitly use umzug.up({ migrations: ['...'] }) and umzug.down({ migrations: ['...'] }).
  • name matches must be exact. umzug.up({ to: 'some-n' }) will no longer match a migration called some-name.
  • umzug.down({ to: 0 }) is still valid but umzug.up({ to: 0 }) is not.
  • umzug.up({ migrations: ['m1', 'm2'] }) is still valid but the shorthand umzug.up(['m1', 'm2']) has been removed.
  • umzug.down({ migrations: ['m1', 'm2'] }) is still valid but the shorthand umzug.down(['m1', 'm2']) has been removed.
  • umzug.up({ migrations: ['m1', 'already-run'] }) will throw an error, if already-run is not found in the list of pending migrations.
  • umzug.down({ migrations: ['m1', 'has-not-been-run'] }) will throw an error, if has-not-been-run is not found in the list of executed migrations.
  • umzug.up({ migrations: ['m1', 'm2'], rerun: 'ALLOW' }) will re-apply migrations m1 and m2 even if they've already been run.
  • umzug.up({ migrations: ['m1', 'm2'], rerun: 'SKIP' }) will skip migrations m1 and m2 if they've already been run.
  • umzug.down({ migrations: ['m1', 'm2'], rerun: 'ALLOW' }) will "revert" migrations m1 and m2 even if they've never been run.
  • umzug.down({ migrations: ['m1', 'm2'], rerun: 'SKIP' }) will skip reverting migrations m1 and m2 if they haven't been run or are already reverted.
  • umzug.up({ migrations: ['m1', 'does-not-exist', 'm2'] }) will throw an error if the migration name is not found. Note that the error will be thrown and no migrations run unless all migration names are found - whether or not rerun: 'ALLOW' is added.

The context parameter replaces params, and is passed in as a property to migration functions as an options object, alongs side name and path. This means the signature for migrations, which in v2 was (context) => Promise<void>, has changed slightly in v3, to ({ name, path, context }) => Promise<void>.

Handling existing v2-format migrations

The resolve function can also be used to upgrade your umzug version to v3 when you have existing v2-compatible migrations:

javascript
const {Umzug} = require('umzug')

const umzug = new Umzug({
  migrations: {
    glob: 'migrations/umzug-v2-format/*.j

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

TypeScriptjavascriptmigrationssequelizetypescript

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言