Grunt‑migrate rollback leaves data changes intact when undo script missing
0 reputation · 02 Nov 2020, 07:32 UTC
0 reputation · 02 Nov 2020, 07:32 UTC
Grunt‑migrate’s grunt migrate:down reverts the last migration file, but only the schema alterations are guaranteed to be undone. When a migration performs data transformations without an explicit down section, the plugin documentation states that no automatic data rollback occurs. This can leave orphaned rows or inconsistent state after a rollback, and there is no built‑in warning or enforcement.
Given that data integrity is critical, the current behavior of grunt‑migrate when handling data changes remains uncertain. Developers must decide whether to rely on manual undo scripts, separate data‑migration tasks, or new tooling to detect missing undo logic.
Grunt‑migrate does not warn or abort a rollback when a migration contains data changes but lacks a matching down function. The runner simply executes whatever down exports (or nothing if it is missing) and marks the migration as rolled back, so any INSERT/UPDATE/DELETE performed in up remains in the database.
node-migrate library that Grunt‑migrate wraps invokes only the down export during grunt migrate:down. If down is absent or empty, no automatic data reversal occurs.node-migrate treat a missing down as a no‑op during down runs, which produces the silent inconsistency described.down that exactly reverses the change (e.g., reverse UPDATE, delete inserted rows by a deterministic WHERE clause, or restore from a backup table).grunt migrate.down rolls back cleanly, but it does not compensate for a missing down.up contains data‑mutation statements while down is missing or trivially empty. Example lint:// grunt‑task: check‑migration‑downs
module.exports = function(grunt) {
grunt.registerTask('check-migration-downs', 'Fail if up mutates data without down', function() {
const fs = require('fs');
const path = require('path');
const migrationsDir = './migrations';
const dataMutations = /\b(INSERT\s+INTO|UPDATE\s+|DELETE\s+FROM)\b/i;
const files = fs.readdirSync(migrationsDir);
let bad = [];
for (const file of files) {
const content = fs.readFileSync(path.join(migrationsDir, file), 'utf8');
const hasUp = /exports\.up\s*=/.test(content);
const hasDown = /exports\.down\s*=/.test(content);
const mutates = dataMutations.test(content);
if (hasUp && mutates && (!hasDown || /exports\.down\s*=\s*function\s*\(\s*\)\s*\{\s*\}/.test(content))) {
bad.push(file);
}
}
if (bad.length) {
grunt.fail.fatal('Migrations missing down for data changes: ' + bad.join(', '));
}
});
};
To confirm whether your specific installation treats a missing down as a silent no‑op or throws an error, we need to know the exact version of grunt‑migrate (or the underlying node-migrate package) you are using. Please provide the version from package.json so we can advise if any version‑specific behavior changes the recommendation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.