If you've ever searched Google for something like:
"How do I roll back one specific MongoDB migration?"
…there's a good chance something already went wrong.
You ran a few migrations. One of them had a bug. And now you don't want to undo everything.
You just want to undo that one migration.
That sounds simple, but if you're using tools like migrate-mongo, you'll quickly discover that rollback doesn't always work the way you'd expect.
I've run into this problem myself, and it's one of the reasons I started using mongo-migrate-kit.
The problem with traditional migration rollbacks
Most MongoDB migration tools treat migrations like a stack.
The basic idea is simple:
- Run a migration → push it onto the stack
- Run
down→ remove the most recently applied migration - Run
downagain → remove the one before that
For a simple project, that's perfectly fine.
But real projects rarely stay simple.
Imagine you deployed three migrations:
Migration A
Migration B
Migration C
Then you discover that Migration B has a problem.
With a stack-based rollback system, you can't simply say:
Undo Migration B.
You first have to roll back Migration C, then Migration B.
Now you've rolled back something that wasn't even broken.
The situation gets even more confusing when you have multiple environments and developers. The "last migration" in your local environment might not be the same as the last migration in staging or production.
And if the migration you want to undo isn't the most recent one at all, you're usually left with two options:
- Roll back several migrations until you reach it.
- Fix the database manually.
I've done the second option before.
I don't recommend it.
What I actually wanted was rollback by migration name
The feature I wanted was very simple:
Roll back this specific migration file.
That's exactly how mongo-migrate-kit works.
The CLI is mmk, and you can roll back a migration directly by its filename:
npx mmk down 20260101120000-the-broken-one.js
That runs the down() function for that migration only.
The other migrations stay exactly where they are.
No rolling back good migrations.
No manually modifying the database.
No trying to remember which migrations need to be reapplied afterward.
Just undo the one you actually meant to undo.
Rolling back an entire release
Sometimes, though, the problem isn't one migration.
Maybe the entire deployment was bad.
For that situation, you can roll back by batch:
npx mmk down --batch 3
A batch represents the migrations that were applied together during one mmk up operation.
So if Batch 3 contained five migrations, this command rolls back that batch as a unit.
This is useful when the problem is the deployment itself rather than one specific migration.
What if I just want to undo the last few migrations?
There's another situation that comes up quite often.
You don't care about a specific batch, and you don't want to specify filenames.
You simply want to undo the last few migrations.
For example:
npx mmk down --steps 2
This rolls back the last two applied migrations, starting with the newest one.
So now there are three different ways to think about rollback:
npx mmk down <file> # Undo one specific migration
npx mmk down --batch <n> # Undo an entire deployment batch
npx mmk down --steps <n> # Undo the last N migrations
They're three different problems, so they should have three different solutions.
Always preview before rolling anything back
Personally, the part I dislike most about production rollbacks is uncertainty.
You don't want to run a command and then discover what it was going to do.
So before rolling back anything important, I preview it first:
npx mmk dry-run down 20260101120000-the-broken-one.js
This doesn't modify the database.
It simply tells you which migrations would be rolled back and in what order.
For production databases, this is something I strongly recommend doing first.
It takes a couple of seconds and can save you from making a much bigger mistake.
What happens if someone edits a migration after it has already run?
This is another problem that's surprisingly easy to create.
Let's say a migration was applied successfully:
20260101120000-add-users-index.js
A few weeks later, someone edits that migration file.
Then someone tries to roll it back.
The problem is that the current down() function might not belong to the same migration code that originally ran against the database.
You're essentially trying to undo something using code that may have changed after the fact.
That can get dangerous very quickly.
mongo-migrate-kit checks for this using SHA-256 checksums.
When a migration is applied, its checksum is recorded.
Before rolling it back, mmk compares the current file with the version that was originally applied.
If they don't match, the rollback stops:
✖ Checksum mismatch: 20260101120000-the-broken-one.js was edited after it was applied
This is intentional.
Rolling back edited migration code can be riskier than applying it.
If you genuinely know what you're doing, you can override the check using --force.
But the important thing is that you have to explicitly choose to do that.
The tool won't silently run potentially different rollback code against your database.
Your migration history also stays intact
Another thing I didn't like about some migration approaches was losing history.
When a migration is rolled back with mongo-migrate-kit, the migration record isn't simply deleted.
Instead, it's marked as reverted and gets a revertedAt timestamp.
That means you can still answer questions like:
- What migrations ran on this database?
- When were they applied?
- Who ran them?
- How long did they take?
- Which migrations were later reverted?
When something breaks in production, having that history available is extremely useful.
Especially at 2 AM.
The short version
If you just want the commands:
npx mmk down <file>
# Roll back exactly one migration
npx mmk down --batch <n>
# Roll back an entire batch
npx mmk down --steps <n>
# Roll back the last N migrations
npx mmk dry-run down <file>
# Preview what will happen without changing anything
That's really the main idea behind the rollback system.
You should be able to choose what you want to undo.
Not be forced to undo everything that happened after it.
Try it
Install the package:
npm install mongo-migrate-kit mongodb
Then, before doing anything risky, preview the rollback:
npx mmk dry-run down <file>
And when you're ready:
npx mmk down <file>
That's it.
If you've ever had to manually fix a MongoDB database because your migration tool couldn't undo one specific migration, you'll probably understand why I built this feature.
You can find the documentation and examples at:
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.