
Key takeaways
• Legacy is a cost problem, not an age problem. Code becomes legacy the day it gets risky and expensive to change, whether it shipped in 2010 or last year.
• You have seven moves, not two. Encapsulate, rehost, replatform, refactor, rearchitect, rebuild, replace. Most owners jump to “rewrite” and pick the most expensive, riskiest one by default.
• The full rewrite is usually the trap. It freezes your roadmap for a year while competitors ship. Reach for it only when the platform itself is dead.
• The Strangler Fig lets you modernize live. Route traffic to new code one slice at a time, with the old system serving users the whole way, so there is no big-bang cutover.
• Start with a code audit, not a rewrite. A one-to-two-week audit tells you which modules to fix, replace, or leave alone before anyone writes a line.
Your product still works. That is exactly why the legacy code inside it is dangerous. Every quarter it costs a little more to change, security patches get harder to apply, and the one engineer who understands the billing module is updating their CV. Legacy system modernization is how you climb out of that corner without betting the company on a rewrite.
Fora Soft is a software development company with a 50-engineer in-house team that has delivered 250+ projects since 2005, and we still run and extend systems we first wrote more than a decade ago. So this playbook is the decision process we actually use with clients, not a vendor brochure. We will be straight about when to leave code alone, when a small refactor pays for itself, and when a rewrite is the move that quietly kills a product.
Why Fora Soft wrote this modernization playbook
Most legacy-code advice comes from two places: enterprise vendors who want to sell you a cloud platform, and consultancies who bill by the year. Neither has to live with the result. We do. On several products we have been the same team for eight, ten, twelve years running, which means every shortcut we ever took eventually came back to our own desk.
That long-run seat changes the advice. We have modernized a 720,000-track music-recognition platform for professional DJs without taking it offline, been the sole team on a HIPAA video-surveillance system used by 770+ US organizations for a decade, and talked more than one founder out of a rewrite that would have burned a year for no new user value. The published depth behind that work lives in our engineering Learn hub.
The pattern we see: teams treat “the code is old” as the problem and “rewrite it” as the answer. Both are usually wrong. The rest of this guide is how to think about it properly, with the numbers to back each call.
Not sure your legacy code is worth saving?
Book a 30-minute call and we will tell you honestly whether to refactor, strangle, or replace it — before anyone quotes you a rewrite.
What is legacy system modernization?
Legacy system modernization is the work of updating old software — its code, its platform, or its architecture — so it costs less to run, carries less risk, and can take on new features again. It runs on a spectrum, from a light cleanup of the code you keep all the way to retiring the system and adopting something new.
Two definitions of “legacy” are worth separating. The engineering one, from Michael Feathers’ book Working Effectively with Legacy Code, is blunt: legacy code is code without tests, because without tests you cannot change it safely. The business one is about money: code is legacy once it is costly or risky to change, no matter how new it looks. A React app from last year with zero tests and a departed author is legacy. A boring, well-tested C# service from 2014 might not be.
Gartner frames the choices as seven options, ordered by how much they cost and how much they disrupt. Figure 1 lays them out so you can see the full menu before you pick.

Figure 1. The seven modernization options, cheapest and least disruptive on the left, most expensive and riskiest on the right.
What legacy code actually costs you
The bill shows up in four places, and only one of them is obvious. First, the direct tax: McKinsey’s 2020 tech-debt study found CIOs estimate technical debt at 20–40% of the value of their whole technology estate, and teams pay an extra 10–20% on top of any project just to work around the debt in the code they touch. A later McKinsey analysis of 220 companies tied the lowest debt loads to roughly 20% faster revenue growth than the most-indebted group.
Second, the hiring tax. When your stack is a dead framework, you are recruiting for skills the market has moved on from, and you pay a premium for the few people who still have them. Third, the security tax: unsupported runtimes stop getting patches, so known vulnerabilities simply stay open. Fourth, the opportunity tax, the quiet one that kills companies. Every feature takes longer because the code fights back, so you ship slower than the competitor who modernized last year.
That last one compounds. The longer untouched legacy code sits, the more each new feature costs, because the mess grows faster than the codebase. Figure 2 shows the shape of it, and why the cheapest time to act is usually now.

Figure 2. Let debt grow and the cost of every change climbs; modernizing early resets the slope.
If you want a number before you commit, get a code audit first. It maps the system, flags the modules that are actually dangerous, and turns “the code is bad” into a costed list of what to fix and what to leave.
The seven ways to modernize legacy code
Here is the full menu in plain words, cheapest first. Read it once before you decide anything, because the right answer is often two or three steps to the left of “rewrite.”
1. Encapsulate. Leave the old code running and wrap it behind a clean API, so new systems talk to the wrapper instead of the mess. Cheapest, least risky, buys you time.
2. Rehost. Lift-and-shift the same code to new infrastructure, for example off an aging on-prem box onto a cloud VM. No code change, lower hosting risk.
3. Replatform. Move it and make small, safe tweaks to fit the new platform, like swapping a self-managed database for a managed one. Same behaviour, modest effort.
4. Refactor. Improve the internal structure of the code you keep, without changing what it does. Add tests, break up the god-class, kill the dead paths.
5. Rearchitect. Restructure the code into new shapes, for example splitting a monolith into services, so it can scale and change independently.
6. Rebuild. Rewrite the component from scratch, keeping its scope. The big one people reach for first and should reach for last.
7. Replace. Retire the system entirely and adopt a different product that already does the job. Sometimes the honest, cheapest answer.
Refactor: fix the code you keep
Refactoring changes how code is written without changing what it does. It is the default for a system that still earns its keep and runs on a supported stack, but has grown tangled. You wrap the risky module in tests, then clean it in small, reversible steps: rename the confusing things, split the 900-line function, delete the code no path reaches. Users notice nothing except that the next feature ships faster.
The discipline matters more than the tooling. Refactor behind tests, ship daily, never mix a refactor with a behaviour change in the same commit. If you want the full method in plain language, we wrote it up separately: code refactoring, when and why.
Reach for refactoring when: the system still fits the business, the platform is supported, and the pain is internal — slow changes and scary deploys — rather than a dead runtime.
Replatform and rehost: move it, mostly as-is
Sometimes the code is fine and the ground under it is the problem: an unsupported OS, a database version past end-of-life, a data centre you want to leave. Rehosting lifts the same code onto new infrastructure. Replatforming does the same but with small, deliberate tweaks to use the new platform properly, such as moving to a managed database or object storage instead of a hand-rolled one.
Neither improves your code, and that is the point. You buy supported infrastructure, security patches, and easier scaling for a fraction of a rewrite, and you do it without touching business logic that already works. It is often the right first step before a deeper refactor, because it stops the bleeding fast.
Reach for replatform or rehost when: the application logic is healthy but the runtime, OS, or hosting is unsupported, insecure, or about to be switched off.
Rewrite from scratch: the tempting trap
A full rewrite feels clean: throw away the mess, start fresh, do it right this time. It is also, in Joel Spolsky’s words, the single worst strategic mistake a software company can make. Netscape rewrote its browser instead of fixing it, went roughly three years between major releases, shipped no version 5 at all, and handed the market to Internet Explorer while the new code was still being written.
The reason is not that new code is bad. It is that the ugly old code encodes years of hard-won fixes: the weird tax rule, the browser quirk, the customer who sends malformed data every Friday. Rewrite from a blank page and you rediscover every one of those bugs the expensive way, in production, while your roadmap sits frozen and competitors keep shipping. The rewrite that ships in “three months” is usually the one that reaches feature parity in eighteen.
Reach for a full rewrite when: the platform is genuinely dead (unsupported language, no path forward), the domain has changed so much the old model no longer fits, and you have a clear spec plus the runway to reach parity. Even then, prefer the Strangler Fig below.
Replace: buy or adopt instead of building
If a system does something generic — email, CRM, a standard admin panel, off-the-shelf auth — the cheapest modernization is often to stop owning it. Replace retires the custom code and moves the job to a product or service that already solves it, and maintains it for you.
The catch is your differentiator. Replace the commodity parts, never the code that is the reason customers pay you. A DJ platform can buy authentication off the shelf; it cannot outsource its music-recognition engine. The skill is drawing that line honestly, and a good audit draws it for you before you sign anything.
Reach for replace when: the system does something commodity that a mature product already does better and cheaper, and it is not the thing that differentiates your business.
Strangler Fig: modernize a live product without a freeze
The Strangler Fig pattern is how you get most of the upside of a rewrite without the freeze. Named by Martin Fowler after the fig that grows around a tree until it replaces it, and documented in AWS’ own guidance, it works like this: put a router in front of the old system, then rebuild one slice of behaviour at a time, and point the router at the new code once each slice is proven. The old system keeps serving everything you have not migrated yet.

Figure 3. Traffic moves from the legacy monolith to new services one slice at a time, with no big-bang cutover.
Why it beats a big-bang rewrite: you ship value in weeks instead of at the end, every slice is small enough to reason about and roll back, and if you run out of budget halfway you still have a partly modernized system that works, not a half-written one that does not. It is more coordination than a rewrite, and the router is real work, but for any product with live users it is almost always the safer bet.
Reach for the Strangler Fig when: you need to replace big chunks of an old system but cannot take it offline, and you want to keep shipping features while you modernize.
Weighing refactor vs rewrite on a live product?
We have run the Strangler Fig on production systems with real users. Let us map a slice-by-slice plan for yours in 30 minutes.
Refactor vs rewrite vs replatform vs replace
The same five questions decide every one of these: how much effort, how much downtime risk, does it keep your domain logic, when does it fit, and what bites you. Here they are side by side.
| Approach | Effort | Downtime risk | Keeps domain logic | Best when |
|---|---|---|---|---|
| Refactor | Low–medium | Low | Yes, fully | Good system, tangled code, supported stack |
| Replatform / rehost | Low | Low–medium | Yes, unchanged | Healthy code, dead or costly infrastructure |
| Strangler Fig rewrite | Medium–high | Low (incremental) | Rebuilt slice by slice | Big change needed, users cannot be frozen |
| Big-bang rewrite | High | High | Re-derived (risky) | Platform truly dead, clear spec, real runway |
| Replace | Low–medium | Medium (migration) | No, you drop it | Commodity job a product already does |
Read the table top to bottom and the pattern is clear: risk and effort climb as you move from fixing the code you have toward replacing it wholesale. Start as high in the list as your situation allows.
What legacy modernization costs: a worked example
Effort, not price, is the honest unit, because a day of engineering costs wildly different amounts depending on where and how you buy it. So price the work in engineer-weeks first, then multiply by your own blended rate. Figure 4 sizes the four paths for the same mid-size app.

Figure 4. Effort ranges for one mid-size app. The big-bang rewrite is roughly double the Strangler Fig for a worse risk profile.
Work a real example. Say you pick the Strangler Fig for a six-year-old SaaS with no test suite: Figure 4 puts that at 16–40 engineer-weeks. At a two-person team and a conservative blended $60 per hour, the low end is 16 × 40 = 640 hours, about $38,000; the high end is 40 × 40 = 1,600 hours, about $96,000. A big-bang rewrite of the same app (30–58 weeks) lands near $72,000–$139,000 and freezes your roadmap the whole time.
Two adjustments make those numbers real. Add a code audit up front (one to two weeks) so you are estimating from evidence, not vibes. And subtract for tooling: our Agent Engineering approach typically trims 25–40% off the build hours by putting AI on the mechanical parts, which we cost conservatively rather than promising the best case. If a vendor quotes you a fixed rewrite price without an audit, that is a red flag, not a bargain.
How AI changes legacy modernization in 2026
AI has made the mechanical parts of modernization dramatically cheaper, which changes the math but not the strategy. The 2026 toolset is real and shipping. Amazon Q Developer upgrades Java 8 and 11 codebases to 17 with step-by-step diffs, and AWS’s transformation tooling also generates documentation for undocumented COBOL and helps decompose monoliths. IBM watsonx Code Assistant for Z translates mainframe COBOL toward Java. GitHub Copilot ships app-modernization flows for Java and .NET dependency and framework upgrades.
What AI is genuinely good at: writing the missing tests that make old code safe to touch, generating documentation for systems whose authors left, doing framework and library upgrades, and drafting the first pass of a service extraction. That is exactly the grunt work that used to make modernization slow and expensive.
What it is not good at, and this matters: deciding whether to refactor or rewrite, understanding why a weird rule exists before deleting it, or shipping unreviewed. AI-generated migration code still needs a human, a test suite, and a review, or you have simply traded old debt for new debt faster. Used well it is a force multiplier on the strategy in this guide, not a replacement for it. If AI is part of your plan, our AI integration team wires it into the existing codebase safely.
A decision framework in five questions
Answer these top to bottom. The first “no” usually points straight at your move, and Figure 5 turns the same logic into a map you can hand to your team.

Figure 5. The five questions as a decision tree; walk the trunk and branch off at the first “no.”
1. Is the system still delivering business value? If no, retire it. Do not spend a cent modernizing something you are about to switch off.
2. Is the platform, runtime, and stack still supported? If no, replatform or rehost first, before you invest in the code that sits on top.
3. Is the domain logic worth keeping? If no — the system does a commodity job — replace it with a product built for that.
4. Can you change it safely today, with tests and reasonably modular code? If yes, refactor in place; you already have the foundation.
5. Do live users make a code freeze impossible? If yes, use the Strangler Fig. Only if you can freeze, have a clear spec, and have real runway does a full rebuild earn a place. When in doubt, book a second opinion before you commit the budget.
Mini-case: modernizing a 720,000-track platform
The situation. Franchise Record Pool runs a Shazam-style music-recognition platform for professional DJs, with a catalogue of more than 720,000 licensed tracks from Sony Music, Universal, Virgin and others, and working DJs (including Funkmaster Flex) depending on it daily. The product could not go dark for a modernization, and the rights-holders would not tolerate downtime on their catalogue.
The plan. Rather than a rewrite, we modernized around the live product, replacing pieces behind the running system so DJs kept working the whole time. Each slice shipped and proved itself before the next one started, which is the Strangler Fig discipline applied to a real catalogue business. The full build is written up in our FRP case study.
The outcome. A modern recognition and catalogue platform that still serves professional DJs and satisfies major-label licensing, delivered without the freeze a big-bang rewrite would have forced. Want a similar read on your own system? Book a 30-minute assessment and we will tell you which of the seven options actually fits.
Want a modernization plan with real numbers?
We start with a code audit and hand you a costed, module-by-module plan — refactor, strangle, or replace — before any build begins.
Five mistakes that sink modernization projects
1. Rewriting before auditing. Teams decide “rewrite” on a gut feeling about how bad the code is, then discover mid-build which parts were load-bearing. Audit first, so the strategy comes from evidence.
2. Modernizing with no tests. Changing legacy code without a safety net means every fix risks a new bug you will not catch until a customer does. Write the characterization tests first; that is what makes the code safe to touch.
3. The big-bang cutover. Flipping from old to new in one weekend concentrates every risk into one night. Migrate incrementally so each step is small and reversible.
4. Modernizing the commodity, not the differentiator. Spending your best engineers rebuilding auth or email while the core product stagnates is effort in the wrong place. Replace the generic, invest in the unique.
5. Treating data migration as an afterthought. Old systems hold years of messy, precious data, and moving it cleanly is often harder than the code. Plan the data path on day one, not the week before launch.
KPIs: how to tell modernization is working
Delivery KPIs. Track change lead time (commit to production) and deployment frequency. Modernization is working when a routine feature that used to take three weeks ships in three days, and deploys go from monthly and scary to daily and boring.
Quality and reliability KPIs. Track change-failure rate and mean time to recovery. Watch test coverage on the modules you have touched climb from zero toward a level where a green build actually means something. Incidents per month should trend down, not up.
Business KPIs. Track the share of engineering time spent on maintenance versus new work; a healthy shift is from the majority going to keeping-the-lights-on toward the majority going to new value. Add hosting cost per active user and time-to-onboard a new engineer, both of which should fall as the code gets clearer.
When not to modernize legacy code
Sometimes the right move is to do nothing, and a firm that only sells modernization will not tell you that. If a system is stable, cheap to run, rarely changes, and is not a security risk, leave it alone. “Old” is not a reason to spend money; boring-and-working is a feature, not a bug.
Hold off, too, when you cannot articulate the business outcome. “The code is ugly” is not a goal; “we need to add SSO and the auth module blocks it” is. Modernize the part that stands between you and a real objective, and only that part. If the whole system is due to be sunset next year, do not modernize it at all — ride it out.
The exception is security. An unsupported runtime with known, unpatched vulnerabilities is not “boring and working,” it is a breach waiting to happen, and that alone can justify a replatform even when nothing else would.
FAQ
What is legacy system modernization?
Legacy system modernization is updating old software — its code, platform, or architecture — so it costs less to run, carries less risk, and can support new features again. It spans a spectrum from a light refactor of code you keep to retiring the system and replacing it with a new product.
Should I refactor or rewrite legacy code?
Refactor if the system still fits the business and runs on a supported stack; you keep all the hard-won logic and ship faster. Rewrite only if the platform is truly dead or the domain has changed fundamentally, and even then prefer an incremental Strangler Fig rewrite over a big-bang one.
How much does legacy system modernization cost?
Price it in engineer-weeks, then multiply by your blended rate. For a mid-size app, a refactor runs roughly 6–14 weeks, a Strangler Fig rewrite 16–40, and a big-bang rewrite 30–58. At a $60/hour blended rate, the Strangler Fig path is about $38,000 to $96,000. A code audit first prices your specific system properly.
What is the Strangler Fig pattern?
Named by Martin Fowler, the Strangler Fig pattern replaces a legacy system incrementally: you put a router in front of it, rebuild one slice of behaviour at a time, and redirect traffic to the new code as each slice is proven. The old system serves users the whole way, so there is no big-bang cutover and no freeze.
How long does legacy modernization take?
A focused code audit takes one to two weeks. After that it depends on the path: a refactor of a mid-size app is often 6–14 engineer-weeks, while an incremental Strangler Fig rewrite is 16–40. The Strangler Fig ships value continuously, so you see results in weeks rather than waiting for a single end date.
Can AI modernize legacy code automatically?
AI accelerates the mechanical parts — writing missing tests, generating docs, upgrading frameworks, and drafting service extractions with tools like Amazon Q Developer and IBM watsonx Code Assistant for Z. It does not decide strategy or ship unreviewed. AI-generated migration code still needs a test suite and human review, or you trade old debt for new debt faster.
What are the biggest risks in legacy modernization?
The classic ones are rewriting before auditing, changing code with no tests, a big-bang cutover that concentrates all risk into one night, spending effort on commodity features instead of your differentiator, and treating data migration as an afterthought. Incremental delivery and a code audit up front defuse most of them.
When is a full rewrite the right call?
When the platform is genuinely dead with no upgrade path, the domain has changed so much the old model no longer fits, and you have both a clear spec and the runway to reach feature parity. Even in that case, an incremental Strangler Fig rewrite is usually safer than freezing the roadmap for a big-bang rewrite.
What to read next
Development
Code Refactoring in Plain Words
The how-to behind the refactor option: when, why, and how to pay down tech debt.
Development
What Is a Code Audit and How to Run One
The step you take before modernizing: process, tools, and pricing for 2026.
Development
Software Code Audit Checklist
A 12-section checklist founders can use to grade a codebase before investing.
Case study
Modernizing a 720K-Track DJ Platform
How we rebuilt a live music-recognition platform without taking it offline.
Processes
Why Time Estimates Miss (and How to Read a Quote)
How to read a modernization quote and spot the padding before you sign.
Ready to modernize without the gamble?
Legacy is a cost problem, not an age problem, and you have seven ways to fix it, not two. Start as far left on the spectrum as your situation allows: encapsulate or replatform to stop the bleeding, refactor the code that still fits, replace the commodity parts, and reserve the rewrite for a platform that is truly dead. When you do need a big change on a live product, the Strangler Fig gives you the upside without the freeze.
The one move that de-risks all of it is starting with a code audit instead of a rewrite, so your strategy comes from evidence. That is where we begin with every client, and we will tell you honestly if the answer is to leave your code alone.
Turn old code into a competitive advantage?
Fora Soft has modernized live products since 2005. Book a 30-minute call and start with a free-standing audit and a costed plan — refactor, strangle, or replace.

