What is technical debt? A practical guide with examples
Technical debt is the future work your software owes. A practical guide to what it means, the main types, real examples, and how to measure what it costs.

Tiago Coelho
CTO


Rehosting changes nothing about the application, replatforming changes what runs underneath it, and refactoring changes the code itself. Cost, risk and elapsed time rise in that order.
AWS calls refactoring "the most complex and costly of the migration strategies" and recommends, for large migrations, modernizing after the move rather than during it.
Rehosting is the only one of the three that doesn't reduce running costs by itself, which is why it so often fails the business case it was sold on.
The decision belongs to the service, not the system. Four questions settle most of them: what's blocking the business, is the code part of the problem, can you verify today's behavior, and will you still own this in three years.
Refactoring is gated by test coverage, not by ambition. On UJET's platform the end-to-end suite grew 4.8x with 43% of it authored by our team, and releases went from monthly to twice a week.
Rehosting, replatforming and refactoring answer the same question with three different amounts of change: how much of the system do you touch while you move it? Rehosting changes nothing. Replatforming changes what runs underneath the application. Refactoring changes the application itself.
Cost, risk and elapsed time rise in that order, and so does what you can do with the system afterward. That's the whole trade, and it's why the question rarely has one answer for a whole product. Checkout, an internal admin tool and a nightly reporting job usually deserve three different decisions.
Rehosting moves an application to new infrastructure without changing it. Replatforming moves it and swaps out components underneath, such as a self-managed database for a managed one, without rewriting the application logic. Refactoring changes the architecture itself to use the target platform properly.
The industry shorthand tells you what each one involves. AWS calls rehosting lift and shift: "you move your applications from your source environment to the AWS Cloud without making any changes." Replatforming is lift, tinker and shift, where you "introduce some level of optimization in order to operate the application efficiently." Refactoring, also called re-architecting, means you "modify its architecture by taking full advantage of cloud-native features."
The taxonomy came from Gartner in 2010, in a note titled Migrating Applications to the Cloud: Rehost, Refactor, Revise, Rebuild, or Replace? Five Rs became six, then seven, as cloud providers added categories. These three are the ones that describe genuinely different amounts of engineering work.
Only one of the differences below is cost, and it's the one that matters least.
Rehosting | Replatforming | Refactoring | |
|---|---|---|---|
Also known as | Lift and shift | Lift, tinker and shift | Re-architecting |
What changes | Nothing in the application | Components underneath it | The application's architecture |
Application code | Untouched | Largely untouched | Rewritten in part or whole |
Relative cost and effort | Lowest | Moderate | Highest |
Risk during the move | Lowest, the system stays the same | Contained to the components you swap | Highest, behavior can change |
What it unlocks afterward | Little on its own | Managed services, lower running costs | Scalability, independent deploys, data restructured for AI features |
Best when | An external deadline sets the schedule | Running costs or operational load are the problem | The architecture is the constraint |
Rehosting makes sense when the deadline is external and the application isn't the problem. A vendor withdrawing support, a hosting contract ending, an acquisition that has to close: these set a date you don't control, and rehosting is the one option that reliably fits inside a date.
It's also the honest choice when you don't yet know enough. Measuring a system in its new environment tells you more than a year of planning documents will, and AWS recommends rehosting for large migrations on the grounds that some applications are easier to optimize once they're already running in the cloud.
Rehosting works well when:
A hard deadline sets the schedule and nothing else does
The application is stable, understood, and not blocking the roadmap
There are more services to move than there is capacity to redesign them
Rehosting falls short when:
The business case rests on lower running costs, because moving a system unchanged usually moves the bill unchanged too
The architecture is what's slowing delivery down, in which case new infrastructure changes nothing
The application depends on specialized hardware, which AWS treats as a reason to retain instead
That first failure mode is the one we see most. Rehosting gets sold internally as a cost reduction and then delivers the same workload on more expensive per-hour infrastructure. Flexera's 2026 State of the Cloud Report, based on more than 750 cloud decision-makers, found respondents estimating 29% of cloud spend as waste, its first increase in five years. Flexera doesn't break that down by migration strategy, but unchanged workloads on instances sized for nothing in particular are a familiar contributor in the systems we assess.
Replatforming makes sense when the application logic is fine and the operational load around it isn't. You keep the code and change what it sits on: a self-managed database becomes a managed one, virtual machines become containers, an unsupported runtime becomes a supported one. The application behaves the same and costs less to run.
This is the option that gets skipped most often in the systems we assess, and it's where replatforming earns the "lift, tinker and shift" name. The tinkering is real work, but it's bounded: you can name the components you're changing before you start, which makes the estimate defensible in a way a refactor rarely is.
Replatforming works well when:
Running costs or operational toil are the actual complaint
An operating system, runtime or database version is out of support and the upgrade is the blocker
Containerizing gets you a deployment pipeline you don't currently have
You want most of the cloud's operational benefit without touching business logic
Replatforming falls short when:
The monolith is the constraint, because a containerized monolith is still a monolith
The component swap turns out to be a rewrite in disguise, which is what happens when application code is coupled to a specific database's behavior
Nobody owns the scope, and "some level of optimization" quietly expands into a refactor with no budget for one
Refactoring makes sense when the architecture itself is stopping the business, and no amount of better infrastructure underneath it will help. A monolith that forces every team to release together, a schema that can't answer the questions the product now needs, a system nobody can safely change: those are architectural problems and they need architectural answers.
It's also the most expensive and the most likely to overrun, and it's worth quoting the platform vendors on that rather than pretending otherwise. AWS's guidance is blunt: refactoring is "the most complex and costly of the migration strategies," and for large migrations, "refactor only when the other migration strategies are not an acceptable option," with modernization recommended after the migration completes. Most internal business cases argue the reverse.
The precondition people skip is test coverage. You can't safely change the shape of a system you can't verify, and a refactor without tests is a rewrite with optimism attached. Test debt is what turns every other kind of debt into something too risky to repay, which is why building the verification layer is usually the first project rather than an overhead on the second.
Pixelmatters is an AI-native Digital Product Studio, and building that layer is much of what our teams do before anything structural moves. On UJET's platform, an AI-powered cloud contact center, the end-to-end test suite grew 4.8x during our engagement with 43% of it authored by our team, and releases went from monthly with a two-week regression cycle to twice a week. Neither number is a refactor. They're what makes one affordable.
Refactoring works well when:
Delivery speed, not hosting cost, is the business problem
The system needs to scale in a way its current shape prevents
Data has to be restructured before anything AI-related is credible
You'll own this system for years, so the payback period is real
Refactoring falls short when:
Test coverage on the critical paths is thin, so the tests are really the first project
The people who understand the original system's decisions have left
Nobody can name what the system will do better in terms the business recognizes
The stack is unfashionable rather than actually a constraint
Four other options sit alongside the three, and two of them cost almost nothing to choose: decommissioning an application, or deciding to leave it alone. Before comparing rehosting, replatforming and refactoring for something, it's worth checking whether you should be moving it at all.
Retire. Decommission it. AWS's own signal for a candidate is a "zombie" workload, averaging under 5% CPU and memory, or no inbound connections for 90 days.
Retain. Leave it where it is, for now. Compliance, data residency, unresolved dependencies or a recent upgrade all make this the right call.
Repurchase. Replace the application with a product, usually moving from a licensed install to software as a service. Often the cheapest answer for anything that isn't differentiating.
Relocate. Move the whole platform rather than the applications on it, for example a VMware estate to its cloud equivalent, with no architectural change.
Retire is the option that gets applied least and saves the most. Every application you decommission is one you don't have to make a decision about, and the least expensive migration is the one that doesn't happen.
Rehosting costs least to execute and often most to run. Refactoring costs most to execute and least to run. Replatforming sits between the two on both. That ordering is stable enough to plan around, and it's why comparing the three on project cost alone produces the wrong answer.
There's a second cost that appears in neither column: deciding badly and finding out in month nine. McKinsey's 2021 survey of cloud programs found companies spending 14% more on migration each year than planned, with 38% seeing migrations delayed by more than a quarter, adding up to more than $100 billion in wasted spend across three years. Those overruns aren't usually caused by the strategy being too ambitious. They're caused by it being chosen once, for everything, rather than per service.
Which puts the useful money at the front. An assessment costing a fraction of a percent of the program is what buys a per-service answer instead of a single guess applied twelve times, and it's the one line item in a modernization budget that reliably pays for itself.
Most systems need all three, applied service by service, and the programs that go wrong are the ones that picked a single strategy and applied it uniformly. "We're moving to the cloud" is a schedule, not a strategy. "We're rehosting these six services, replatforming these four, refactoring the two that block the roadmap, and retiring these three" is a strategy.
Sequencing matters as much as selection. Rehosting first and refactoring later is a legitimate plan, and often the right one, but only if the refactor is funded and scheduled rather than assumed. The pattern we see most often is a rehost sold as phase one of two, where phase two never got a budget line and the company now runs its old architecture at cloud prices.
Where something does need re-architecting, the strangler fig pattern that Martin Fowler described remains the least risky way to do it: stand the new implementation up alongside the old one, route traffic across piece by piece, and keep both running until the old one has nothing left to serve. It's slower than a rewrite on paper and faster in practice, because it never requires a date on which everything changes at once.
That's the case for small and continuous over big and singular. The improvements compound, and what usually stands between a system and a better one isn't the code. It's inertia.
Start with the constraint, not the option. Four questions, in this order, resolve most services without a workshop.
What's actually blocking the business? If it's a deadline, rehost. If it's running cost or operational load, replatform. If it's delivery speed or the shape of the data, refactor. Naming the constraint first is what stops you choosing a strategy and then hunting for a justification.
Is the application code part of the problem? If the logic is sound and only its surroundings are painful, you're replatforming. If the logic itself can't express what the business now needs, you're refactoring, and no infrastructure change will substitute.
Can you verify the system's behavior today? Test coverage on the critical paths is the gate on refactoring. Where it's thin, building it is the first project, not an overhead on the second.
Will you still own this system in three years? Refactoring only pays back over years. For anything being sunset, sold or replaced inside that window, retire or repurchase is usually the better answer and rehosting is the fallback.
One more, worth asking out loud: if the program stops after phase one, what have you got? A stalled rehost leaves you the same system on someone else's hardware. A stalled replatform leaves you lower running costs. A stalled incremental refactor leaves you the parts you already moved, working. That asymmetry is a decent tiebreaker when two options look close.
Answering those five for a real system is bounded work, and pricing it separately from the migration keeps it honest. Our own discovery and pilot engagements start at €5k, which is the order of magnitude worth spending to find out which services deserve which of the three. Whoever runs it, run it before committing a year of engineering to the answer.
Rehosting, replatforming and refactoring aren't competing philosophies. They're three sizes of intervention, and the job is matching each workload to the smallest one that removes the constraint.
What makes modernization programs fail isn't picking the cautious option. It's picking one option for everything, then discovering in month nine that the system wasn't uniform. It never is. Sorting services by what's actually blocking each one, and being willing to give a single product three different answers, is unglamorous work, and it's what decides whether the system you're holding in three years can carry whatever comes next.
Replatforming is moving an application to new infrastructure while changing the components underneath it, without rewriting the application logic. Typical examples are swapping a self-managed database for a managed one, moving virtual machines to containers, or upgrading to a supported runtime. AWS calls it "lift, tinker and shift". The application behaves the same and usually costs less to run.
Replatforming changes what the application runs on. Refactoring changes the application. If you can name the components you're swapping before you start and the business logic stays untouched, you're replatforming. If the architecture itself has to change, so that the way the system is decomposed is different afterward, you're refactoring. Refactoring costs more, takes longer, and is the only one of the two that fixes an architectural constraint.
Rehosting changes nothing about the application or its components: it's the same system on different infrastructure, which is why it's called lift and shift. Replatforming changes components underneath the application, such as the database or the runtime. Rehosting is faster and lower risk. Of the two, replatforming is the one that reduces running costs.
Yes. Lift and shift is the common name for rehosting, and AWS uses the terms interchangeably in its own migration guidance. Both mean moving an application to a new environment with no changes to the application itself. The related term "relocate" is different: that means moving a whole platform, such as a VMware estate, rather than the individual applications running on it.
Mostly, yes. In ecommerce, replatforming usually means replacing one commerce platform with another, such as moving from Magento to Shopify. In cloud migration terms that's closer to repurchase than replatform, because you're adopting a different product rather than changing the infrastructure under your own code. The word is the same and the work is not, which is worth clarifying early in any conversation where both meanings are in play.
No, and the overlap causes real confusion. In everyday engineering, refactoring means improving code structure without changing behavior, usually in small continuous increments. In the migration taxonomy, refactoring means re-architecting the application to use the target platform properly, which often does change how the system behaves. The first is routine hygiene. The second is a program with a budget.
Rehosting is measured in weeks per application and can run hundreds in parallel, which is why it suits deadline-driven programs. Replatforming is typically weeks to a few months per application, depending on how many components change and how tightly the code is coupled to them. Refactoring runs months to years, and is the one where estimates are least reliable. Timelines vary too much by system to promise numbers.
Yes, and AWS recommends exactly that for large migrations: move first, modernize after. The condition is that phase two has a budget and a date. Where it doesn't, the organization ends up running its old architecture on cloud infrastructure, paying more than before with none of the benefits it moved for. If the refactor is genuinely deferred rather than abandoned, write down which workloads it applies to before phase one starts.
Not always, but data is usually the gate. Retrieval and agent features depend on data being consistent and accessible, and in older systems it typically isn't, which makes data debt the first thing to restructure rather than the application. That's often a narrower project than a full re-architecture. Where the blocker is genuinely the architecture, the honest answer is that the AI work waits on it.

Tiago Coelho
CTO
Tiago Coelho is the CTO of Pixelmatters, a Porto-based AI-native Digital Product Studio that has shipped software for clients including Checkr, Glean, and VMware. An engineering leader who helped shape the studio's engineering processes, handbook, and quality practices, he writes about technology strategy, and engineering management.
Share this article