Migration projects always start the same way.
Clear scope.
Defined timeline.
A plan to “move everything” from old to new.
And they almost never finish.
Not because of bad planning.
Because the system doesn’t stand still.
Migration assumes a stable system
Every migration plan is built on a simple assumption:
the system you’re migrating will remain consistent.
But in reality:
- new features are added
- bugs are fixed
- configurations change
- dependencies evolve
The system is moving while you’re trying to copy it.
Which means:
you’re always behind.
You’re not moving a system — you’re chasing it
Migration is often described as a transfer.
But it behaves more like synchronization.
You move part of the system.
Meanwhile, the original changes.
So you update the migration.
Then it changes again.
This is why migration timelines stretch indefinitely.
Because the target keeps shifting.
Old and new systems start coexisting
At some point, migration stops being a transition.
And becomes a state.
- part of the system runs on old infrastructure
- part runs on new
- both need to stay consistent
This creates:
- duplication
- complexity
- synchronization logic
And removing the old system becomes harder than expected.
Hidden complexity slows everything down
Migration exposes what rewriting hides.
Edge cases.
Implicit behavior.
Undocumented dependencies.
This is the same issue described in Why Software Rarely Gets Rewritten From Scratch.
The system contains more than its code.
And migration forces you to deal with all of it.
No one fully understands what needs to be moved
Modern systems are too complex to fully map.
As described in The Systems Nobody Fully Understands Anymore:
knowledge is distributed, incomplete, and often outdated.
Which means:
you don’t know exactly what you’re migrating.
Until something breaks.
Configuration drift breaks assumptions
Even if the system was documented once, it’s no longer accurate.
Over time:
- environments diverge
- configs change
- behavior shifts
This is the effect described in Configuration Drift: The Silent Killer of Infrastructure.
Migration assumes consistency.
Reality provides variation.
You can’t stop the system to migrate it
In theory, you could freeze everything.
Migrate.
Then restart.
In practice, you can’t.
Because systems are now infrastructure.
As described in When Daily Life Depends on Software Infrastructure:
they need to keep running.
Continuously.
Which means migration must happen live.
And that makes everything harder.
Risk increases as migration progresses
Early migration looks simple.
Small components.
Low impact.
But as you move deeper:
- dependencies increase
- complexity grows
- risk compounds
This is part of the fragility described in The Fragile Infrastructure Behind “Always Online” Services.
You’re not just moving code.
You’re moving a system that everything depends on.
Failure doesn’t stay isolated
A migration issue rarely affects just one component.
Because systems are interconnected.
As described in Why Modern Systems Fail All at Once:
failures propagate.
Which means migration mistakes scale quickly.
Migration doesn’t end — it gets absorbed
At some point, something changes.
The migration is no longer a project.
It becomes part of the system itself.
- ongoing
- incomplete
- continuously updated
Not because it failed.
Because the system evolved faster than the plan.
Migration projects don’t fail because teams are incapable.
They fail because systems are dynamic.
You can’t fully migrate something that never stops changing.
And the longer it takes,
the more the system you’re trying to reach
no longer exists in the form you planned for.