Ask around and you’ll hear some version of the same story from almost every team that’s done a cloud migration: the estimate was wrong, not by a little, but by something close to double. This isn’t a case of a few unlucky teams underestimating. It’s consistent enough across otherwise disciplined teams that the estimate itself is worth examining, not just the execution.
Why the Estimate Is Wrong in a Predictable Direction
Migration estimates are almost always built around moving the known, well-understood parts of the system: the application code, the primary database, the obvious dependencies. Those parts move roughly on schedule, because they were scoped accurately — they were visible, documented, and easy to reason about before the project started.
What blows the timeline is the part that wasn’t scoped at all, because nobody knew it existed until the migration surfaced it: the script someone wrote three years ago that nobody remembers, running on a cron job on a server that was never in the architecture diagram. The integration that quietly depends on a specific IP address instead of a hostname. The permission structure that worked by accident in the old environment and breaks the moment it’s rebuilt correctly in the new one. None of this shows up in a pre-migration audit, because a pre-migration audit surfaces what’s documented, and this category of problem is defined by not being documented.
The Two Kinds of Migration Work
Moving what you know about. This is the part that gets estimated, and it’s usually estimated reasonably well, because it’s genuinely knowable in advance. Application servers, primary databases, the infrastructure that shows up on an architecture diagram.
Discovering and fixing what you didn’t know about. This is the part that doesn’t get estimated at all, because it can’t be — you don’t know the scope of a problem you haven’t found yet. This work isn’t a delay caused by the migration going badly. It’s the actual migration, revealing itself as it happens.
The consistent doubling isn’t teams doing the first kind of work badly. It’s teams estimating only the first kind of work and discovering the second kind exists at roughly the same scale, every time, regardless of how careful the initial audit was.
What Actually Helps
Budget explicit time for discovery, not just execution. A migration plan that allocates time only for moving known components is, by construction, a plan for half the actual project. Building in a discovery phase — with its own budgeted time, not treated as buffer stolen from execution — acknowledges that the undocumented half of the system is real work, not a risk to be avoided through better planning.
Treat the first migrated environment as a discovery tool, not a final answer. Moving a lower-stakes environment first — staging, not production — isn’t just risk reduction. It’s specifically how the undocumented dependencies get found, because they only reveal themselves when something actually breaks in the new environment. Estimating the production timeline before that discovery phase has run is estimating with information you don’t have yet.
Communicate the estimate as a range with a stated confidence level, not a date. A single date implies a level of certainty the estimate doesn’t actually have, and it sets up the “we’re behind schedule” narrative the moment discovery work starts eating into the timeline — even though that discovery work is normal, expected migration work, not a failure. A range, with the reasoning behind the range, sets a more honest expectation from the start.
Don’t let the estimate get locked in before any discovery work has happened. The most common mistake isn’t the estimate being optimistic — it’s the estimate being finalized and communicated to stakeholders before any actual investigation of the undocumented parts of the system has occurred. Once a date is committed publicly, the discovery-phase findings become “problems” instead of “expected work,” which changes how the whole project gets perceived internally even though the actual timeline reality didn’t change.
The Bottom Line
Cloud migrations don’t consistently run over because teams are bad at estimating. They run over because the estimate is built around the half of the system that’s knowable in advance, and the other half — the undocumented dependencies that only surface once you actually start moving things — isn’t a planning failure. It’s the actual work. Budgeting for it explicitly, instead of discovering it as a delay, is the difference between a migration that’s roughly on schedule and one that’s roughly twice as long.