Skip to Content

Insights

Moving a live operational system without stopping the operation

You cannot pause a logistics business for a migration weekend. Trucks arrive on Sunday. What follows is what we learned doing it module by module instead.

2 September 2026 · 7 min read

The big-bang cutover is the tempting one

Move everything at once, over a weekend, and be done. It is tempting because it is simple to plan and because the alternative — running two systems in parallel — sounds like twice the work.

It fails badly when it fails. Every module's problems arrive simultaneously, at the worst hour, with no way to tell which failure caused which. And rolling back is not the clean undo people imagine, because by then the new system holds writes the old one has never seen.

Move one module at a time

Migrating module by module turns one enormous risk into a sequence of small ones. Each move is small enough to verify properly and small enough to reverse while nobody is depending on it.

This is far easier when modules are genuinely separate in the database — separate schemas, no foreign keys reaching across them. If that separation exists, a single module can be dropped and restored repeatedly without touching the others, which means you can rehearse each move as many times as you need.

If that separation does not exist, discovering so during a migration is not the moment you want to find out. Check for cross-module references before planning anything.

"We deployed the new frontend" does not mean users have moved

This is the lesson that cost us the most and generalises the furthest. You deploy the new frontend, announce the switch, and assume traffic has moved. It has not.

Browser tabs left open for days keep talking to the old backend. Installed mobile apps carry the old URL until someone updates them. Cached web apps keep serving an old bundle. Each of those keeps writing to the system you believe is retired, and those writes are invisible unless you look for them deliberately.

Prove the old side is idle, do not assume it

Before retiring anything, measure both sides. Two checks are cheap and decisive.

First, the most recent login on each side — if people are still authenticating against the old system, they are still using it. Second, database statistics for updates and deletes: a freshly restored copy contains only inserts, so any update or delete on a table is a human writing there after the restore. Either signal means the migration is not finished, whatever the deployment status says.

In the end the only reliable way to stop writes to the old system is to switch it off. Every softer measure is a request that some client, somewhere, will ignore.

Business numbers collide when two systems are live

Any sequence that produces a number a human quotes — consignment notes, invoices, job numbers — becomes dangerous the moment both systems can issue them. Both sides continue from the counter they know about, and you get two documents with the same number and different contents.

For a handful of records created during the gap, re-entering them on the new side beats importing them. Importing preserves the collision; re-entry resolves it, and someone reads each record while doing it.

Expect to lose something, and decide in advance what

Every real migration has a small loss ledger: a batch reprinted, a few test records discarded, files that were never on persistent storage in the first place. Pretending otherwise leads to discovering the losses later, unrecorded.

Write the ledger as you go, tell the person who owns the data, and get their agreement on each item. A known, accepted loss is a decision. An unknown one is an incident, usually surfacing weeks later when someone goes looking for a document.

What we would do the same way again

  • One module at a time, with the riskiest one first while attention is highest
  • Verify per module with real probes, not with the deployment log
  • Keep the old system reachable but switch it off the moment the module is confirmed moved
  • Re-enter the handful of records created during the gap rather than importing them
  • Restore a backup into a scratch database and check it before trusting any of it
  • Write the loss ledger down and have it accepted, item by item

It is boring when it works

A migration done this way produces no story. Users notice a short pause, if anything, and the business carries on. That is the entire objective, and it is worth resisting the plan that gets you there faster.

Running into this?

We build these systems for logistics operators in India. Describe your situation and we will tell you honestly what we would do.

Start a conversation
Contact us