DEV Community

Cover image for How to Roll Back a Single MongoDB Migration (Without Nuking the Rest)
Santosh Gupta
Santosh Gupta

Posted on

How to Roll Back a Single MongoDB Migration (Without Nuking the Rest)

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 down again → 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
Enter fullscreen mode Exit fullscreen mode

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:

  1. Roll back several migrations until you reach it.
  2. 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Then, before doing anything risky, preview the rollback:

npx mmk dry-run down <file>
Enter fullscreen mode Exit fullscreen mode

And when you're ready:

npx mmk down <file>
Enter fullscreen mode Exit fullscreen mode

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:

https://mongo-migrate-kit.vercel.app

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.