Releases and deprecation
Removing a table or column right away breaks the version of your application still running during a deployment, and every older version you might roll back to. db-migrate removes them in stages instead, along the releases of your application.
Releases need db-migrate 1.5.0 and v2 migrations.
Releases
A migration starts a release with _meta.release:
exports._meta = {
version: 2,
release: '2.3.0'
};
The label can be anything, a version, a date or a name. db-migrate does not
interpret it, it only counts the releases in the order of the migrations: a
migration without release belongs to the release before it. Two releases
after 2.3.0 are the second and third label following it, whatever they are.
Deprecating
exports.migrate = async db => {
await db.deprecateTable('legacy_orders');
await db.deprecateColumn('users', 'fax');
};
marks the table and column in the release of the migration, call it R. Your
application stops using them in R. A column with notNull is relaxed, so the
application can stop writing it (not with sqlite, which can not change
columns).
| R | marked, notNull of a column relaxed |
| R+1 | renamed to __dbm_deprecated_<name>_<time>, with the time of the migration deprecating it, whatever still uses it fails now, while the data is still there |
| R+N | dropped, with drop: 'auto' only |
The renaming and dropping happen before the first migration of the release, logged as:
[INFO] [release] starting release 2.4.0
[INFO] [release] renaming the deprecated table "legacy_orders" to __dbm_deprecated_legacy_orders_20261009120000
Dropping
N is 4 by default. With drop: 'manual', the default, nothing is dropped.
Once due, up and check warn about it:
[WARN] [release] the deprecated table "legacy_orders" is due for dropping, deprecated 4 releases ago. Drop it in a migration with db.dropDeprecated("legacy_orders").
Drop it in a v2 migration:
// everything due
await db.dropDeprecated();
// one table or column, due or not
await db.dropDeprecated('legacy_orders');
await db.dropDeprecated('users', 'fax');
With drop: 'auto' db-migrate drops it on its own after N releases. Set
the options per call or for the project:
await db.deprecateTable('legacy_orders', { releases: 2, drop: 'auto' });
{
"deprecation": {
"releases": 2,
"drop": "auto"
}
}
The project options go into .db-migraterc, or cmdOptions of the
programmable API.
Reverting
Reverting the migration deprecating a table or column removes the mark,
and relaxing notNull is reverted. Reverting the first migration of a
release reverts what was done before it, a renamed table or column gets its
name back, a dropped one is created again, without its data.
db-migrate fix learns the renaming and dropping of the releases again,
since db-migrate 1.6.0.
Rows deleted in soft mode
A soft delete keeps the rows, until they
are purged. With purge, they are purged along the releases as well:
await db.delete('sessions', { expired: true }, {
mode: 'soft',
column: 'deleted_at',
purge: { releases: 2, drop: 'auto' }
});
purge: true takes the options of the project. Once due, the rows are
purged before the first migration of the release with drop: 'auto', or
warned about with drop: 'manual' until db.purge purges them. A release
which purged rows can not be reverted, down refuses it before reverting
anything.
Backups of data migrations
update and delete of data migrations keep the rows
they changed in backup tables, to revert the migration. Once a data migration
ran N releases ago, it is considered final: with drop: 'auto' its backups
are dropped before the first migration of the release, with drop: 'manual'
up and check warn until a data migration drops them:
// the backups of all data migrations due
await db.dropBackups();
// of one migration, due or not
await db.dropBackups('20261009120000-orders');
A data migration whose backups are dropped can not be reverted anymore. The
options are the same as for deprecations, deprecation: { releases, drop }.
Since db-migrate 1.7.0.