


“Companies pay an additional 10 to 20 percent to address tech debt on any project.” — McKinsey & Company




“The bottom 20% for tech debt are 40%more likely to have canceled modernizations.” — McKinsey & Company

















The trigger is usually one of four: the maintenance bill has outgrown the value delivered, the framework or runtime is past end of life and no longer patched, new integrations or features are blocked by the architecture, or the people who understand the code are leaving. McKinsey puts technical debt at about 40% of IT balance sheets, which is the running cost of waiting on all four.
Four approaches cover most cases: rehosting moves the application to modern infrastructure without changing its code, replatforming adapts it to a managed runtime or database, refactoring and rearchitecting change the code structure, often extracting services from a monolith with the strangler pattern, and rebuilding recreates the application from captured behavior. The full seven-option framework and the criteria for choosing between them are covered in our legacy modernization strategy guide.
Not always, and that is the first thing an assessment should establish, because a system that is stable, cheap to run, and not blocking anything is often better left alone given the migration risk, data risk, and cost of rebuilding undocumented behavior. Replacement pays off when the system blocks revenue, fails audits, or costs more to maintain than a modern equivalent would cost to build and run.
The old system keeps serving traffic while functionality moves across in pieces: a routing layer in front, parallel operation of old and new paths, validation of data on both sides, and a rollback route at every step. Work is sequenced so the highest-risk component is never the first one moved, and an Azure release-management program run this way held 99.999% availability throughout.
Cost follows the state of the codebase and how much behavior is undocumented, the number of integrations that must keep working during the transition, the volume and quality of data being migrated, whether compliance applies to the migration itself, and the path chosen, with rehosting and rebuilding at opposite ends. Timelines scale with integrations rather than codebase size, and both are set after the assessment maps dependencies, because before that any estimate is a guess.
Older stacks change the approach more than the goal: behavior lives in code nobody documented and in people who are retiring, so the first phase captures that behavior as tests before anything moves. Delivered upgrades include Ruby 2.6.3 to 3.0 and Rails 4.2 to 7.0 under production load, and mainframe and COBOL modernization are covered in dedicated guides.
Data migration runs as its own workstream with its own validation: profiling the source before moving it, reconciling record counts and business totals on both sides after each batch, keeping the old store readable until reconciliation passes, and defining in advance what a failed migration rolls back to. Quality issues found during profiling are decided on before migration begins, not discovered after it ends.
Modernization that swaps one vendor dependency for another has moved the problem rather than solved it. The practical guards are infrastructure defined as code so environments reproduce elsewhere, provider-specific services isolated behind interfaces the application does not depend on directly, open formats and standard protocols at integration boundaries, and managed services chosen only where the exit path is documented before the entry path is built.