Strangler Pattern Applied to AI-Generated Codebases
Modernize AI-generated code incrementally, not all at once, to avoid downtime and rebuild correctly.

AI-generated codebases are hitting a version of the legacy modernization problem, except compressed into months instead of decades. The code that ships from tools like Lovable, Bolt, v0, and Claude Code works in the demo. It also arrives entangled, undocumented, and structurally opaque in ways that make a full rewrite the wrong move for any founder who can't afford downtime. The fix borrows from a pattern that's been solving this exact shape of problem since 2004: the strangler fig.
How quickly AI-generated technical debt becomes visible in production
The timeline is oddly consistent across teams that build fast with AI tools. Month one feels great. Features ship in hours that would've taken a human developer days. By month three, something shifts: every change starts breaking something unrelated, and nobody can point to why. By month six, the team is measurably slower than before it adopted AI tooling in the first place.
Why does this happen so predictably? Follow the code duplication. GitClear's analysis of commits found duplicated code blocks rose eightfold in 2024, while refactoring activity dropped to its lowest point in GitClear's dataset. That's the fingerprint of AI-assisted development at scale: models solve the immediate problem in front of them by copying and adapting, not by abstracting. Nobody's going back to clean it up, because going back requires understanding what the duplicated logic actually does, and that context often doesn't exist anywhere except inside the original generation.
Research into open-source repositories that adopted AI coding tools has found substantial jumps in code complexity and static analysis warnings after adoption. That lines up with developer-reported experience: in the 2025 Stack Overflow Developer Survey, a majority of respondents said they spend more time fixing "almost-right" AI code than they expected to, and close to half said debugging AI-generated code takes longer than debugging code a human wrote from scratch.
Security is where this gets dangerous rather than just annoying. Across multiple studies, a large share of AI-generated code contains vulnerabilities mapping directly to the OWASP Top 10, and in Java specifically, failure rates on security benchmarks exceed 70%. The 2025 CVE-2025-48757 incident on the Lovable platform is the concrete version of this: applications generated through the platform shipped with absent or misconfigured Postgres row-level security policies. A material share of the deployments analyzed after the disclosure were leaking PII, financial records, and hardcoded API keys to anyone who appended the right query parameter to an endpoint.
There's a newer term for the underlying condition: GenAI-induced technical debt that developers themselves flag but never resolve. It's debt that doesn't come from someone consciously cutting a corner to hit a deadline. It comes from nobody knowing what a given block of AI-generated code actually does, or why it does it that way. That's what makes it dangerous. Debt you chose is debt you can find. Debt nobody remembers choosing is invisible until a real user hits the one input the model never accounted for.
Why big-bang rewrites fail the founders who most need to avoid downtime
Faced with a codebase like that, the instinct is obvious: burn it down and start clean. It feels like the responsible move. It's usually the wrong one, and the reason has less to do with engineering pride and more to do with arithmetic.
A rewrite treats modernization as a single project with a single delivery date. Everything freezes until that date arrives. AWS's own guidance on the strangler fig pattern is blunt about this: while a system is being refactored in one big push, it becomes extremely difficult, sometimes flatly impossible, to ship new features at the same time. For a founder trying to close customers and grow revenue, this is a real obstacle rather than a technical inconvenience. That's the business on pause.
Worse, a rewrite demands that someone reconstruct all the undocumented business logic buried in the old system, correctly, in one attempt, before the new version goes live. With a human-written legacy system, at least some of that logic lives in commit history, code comments, or a departed engineer's memory. With AI-generated code, much of it never had a documented rationale to begin with. The model made a decision, the decision worked, and the reasoning behind it went unrecorded.
The failure rate backs this up. NRI Digital Consulting's 2026 analysis put the failure or underperformance rate of modernization projects somewhere in the range of the high sixties to high seventies percent. This is a common situation rather than an edge case. That's closer to the default outcome.
Two enterprise stories make the mechanism concrete. TSB Bank's 2018 single-event migration of customer accounts locked customers out en masse, exposed accounts to fraud, cost the bank a nine-figure sum, drew a regulatory fine in the tens of millions of pounds, and ended with the CEO's resignation. Knight Capital's 2012 deployment is the other cautionary tale: a dormant legacy code path got reactivated during a partial rollout and burned through hundreds of millions of dollars in under an hour. Neither company failed because modernizing was the wrong call. Both failed because there was no mechanism to isolate risk, test incrementally, or roll back when something went wrong.
Scale that down to a founder with a live product and paying customers, and the math gets harsher, not gentler. A broken signup flow or a corrupted database migration during a rewrite cutover can lose a customer permanently. There's no regulatory backstop waiting to absorb the damage, and there's no brand equity built up over decades to cushion the fall.
What the strangler fig pattern actually does and why the mechanics fit this problem
Martin Fowler named this pattern in 2004, borrowing the image from strangler fig trees native to Queensland, Australia. The vine germinates in a nook of a host tree, sends roots down to the soil over time, and gradually replaces the host entirely, eventually strangling it. The tree doesn't fall down one day and get replaced overnight. It's replaced piece by piece, while it's still standing.
The pattern translates into three operational steps. First, install a routing façade in front of the existing system. At the start, it changes nothing: every request passes through to the legacy system exactly as before. Second, pick one slice of functionality, build it properly in a new system, and redirect just that slice through the façade. Third, repeat that process, slice by slice, until the legacy system has nothing left to do, at which point it gets decommissioned.
The façade is the part that makes this safe for a product people are actively using. Users never experience a cutover moment. Requests get routed to whichever system currently owns that piece of functionality, and that routing can be adjusted with a feature flag rather than a full deployment. Rolling back a broken extraction becomes a configuration change instead of an emergency redeployment at 2 a.m.
So why does this map so cleanly onto AI-generated codebases specifically? Because an AI-generated MVP is, structurally, a monolith. No defined service boundaries. No documented domains. Functions that handle three unrelated responsibilities because the model needed them to work together in that one demo flow. Installing a façade doesn't require understanding the entire interior of that system first, which matters enormously when the interior is genuinely opaque even to the people who "built" it. Each slice extracted behind the façade can be built with proper data modeling, error handling, and monitoring baked in from day one, rather than needing the whole system to be correct simultaneously.
In practice, the façade is usually a reverse proxy (Nginx, AWS ALB) controlling where traffic goes, paired with canary releases that route a small slice of users to the new component before expanding to everyone. And because the old system keeps running the parts that haven't been extracted yet, new feature development doesn't have to stop. The whole advantage over a freeze-and-rewrite is that the business keeps moving while the foundation gets replaced underneath it.
The decisions that determine whether a strangler migration succeeds or stalls
The pattern itself is not the hard part. It's well-documented, well-tested, and mechanically simple. What determines whether a migration actually finishes is a set of judgment calls that have nothing to do with the technical concept and everything to do with sequencing and discipline.
Getting the boundaries wrong before extraction starts. AWS's guidance is direct about this risk: premature decomposition gets expensive fast, especially when the domain isn't well understood, and it's entirely possible to draw service boundaries in the wrong place. Teams that skip the domain analysis step tend to extract services that mirror the accidental structure of the old codebase rather than the actual shape of the business. That doesn't fix the tangle. It just moves the tangle into a new system with better hosting. For AI-generated code specifically, this risk is sharper: the model followed no domain model when it wrote the original code, so there's no structure worth reverse-engineering. The boundaries have to come from how the business actually works, not from how the code happens to be organized.
Stalling out after the easy wins. The first few extractions tend to deliver the most visible value, fastest. Momentum is high, the win is obvious, everyone's motivated. Then the tail arrives: the smaller, weirder, harder-to-isolate components that don't offer the same dopamine hit when they're done. Migrations often stall right there, leaving two systems running side by side indefinitely. That doubles the maintenance burden and keeps the legacy code alive "just in case," which is a polite way of saying it never actually gets retired. The fix is almost administrative: write the retirement criteria for the legacy system before migration begins, so the conditions for shutting it down are fixed in advance rather than negotiated away later.
Letting the façade become fragile itself. The routing layer is a permanent load-bearing part of the system. It's production infrastructure from the moment it goes live, and it needs one person accountable for its behavior. Data synchronization between the old and new systems also needs explicit design, since the two will temporarily share or duplicate state. Skip that design step, and the complexity that used to live inside one messy system now lives in the gap between two systems, which is arguably worse.
Documentation matters more here than it would in a shorter project, if only because migrations stretch across months and memory fades. Architectural decision records and updated diagrams after each phase aren't bureaucratic overhead. They're the mechanism that lets someone joining the project in month four understand what happened in month one without having to reconstruct it from git blame.
A practical sequencing guide for applying the pattern to an AI-generated MVP
Phase 0: audit before touching anything. Map what the codebase actually does, not what the original spec said it should do. Those two things diverge more than people expect with AI-generated code, since the model made small interpretive choices along the way that never got reviewed. Flag which functions touch user data, payment flows, authentication, or third-party APIs. Those are the highest-risk, highest-priority candidates for extraction. Document the GIST debt explicitly: which parts of the system does nobody on the team feel confident explaining? That list is the real starting map, not the architecture diagram nobody drew.
Phase 1: install the façade, change nothing yet. The façade goes in front of the system and passes every request through unchanged at first. That's the discipline that keeps the first extraction from turning into an accidental big-bang rewrite. It proves the façade works before it's asked to route anything. Add monitoring, logging, and error tracking at this layer too, since that's likely the instrumentation the AI-generated MVP never had in the first place.
Phase 2: sequence extractions from highest-risk to lowest-ambiguity. Authentication and session management usually come first. AI tools generate these insecurely often enough that rebuilding this piece early removes the widest vulnerability surface in one move. The data access layer comes next: the flat objects or single-table models typical of an AI-generated MVP can be swapped out behind the façade without the application layer even noticing, which unblocks everything that comes after it. External integrations, payments, email, third-party APIs, follow. These tend to carry hardcoded keys and fragile integration points, and each one is a self-contained slice that's easy to isolate and rebuild cleanly.
Phase 3: validate with canary routing before full cutover. Route a small percentage of production traffic to the new component. Watch error rates, latency, and data integrity before expanding further. If something's off, the feature flag flips back instantly. No redeploy, no incident response scramble.
Phase 4: enforce the retirement criteria written back in phase 0. The specific conditions for turning off a legacy path need to be decided in advance, not negotiated in the moment when someone gets nervous about pulling the plug. Skip this step, and the old code becomes a zombie system: technically unreachable, still running, still a maintenance liability nobody's tracking.
What a founder without a technical team needs to make this work
The strangler pattern was practically built for constrained teams. It doesn't demand a large engineering org to execute. It does demand continuous technical ownership across every phase, which is a different requirement entirely, and one that's easy to underestimate.
The façade needs a single owner: someone who understands the routing logic, watches how it behaves in production, and makes the sequencing calls for each extraction. This role requires continuity rather than rotating between whoever's available that week.
What does a long-term engineering partner offer here that a freelancer or a short, one-off agency engagement usually doesn't? Context continuity is the big one. Decisions made in phase 1 directly shape what's possible in phase 3, and losing that context between hired hands is one of the more common reasons these migrations quietly stall out. Retirement discipline is the other piece worth naming: an outside contractor brought in for a single engagement has no real incentive to push for decommissioning the legacy system. That decision needs someone accountable for the long-run cost of running two systems in parallel, not someone who's paid out and gone before that cost shows up on a bill.
What happens after the migration technically "finishes" still matters." The new components built during extraction still need monitoring, still need updates, still need incremental improvement as usage patterns shift. The migration doesn't end in a tidy handoff document. It becomes the new baseline the product keeps building on.
Handled this way, the founder gets to stay focused on the part of the business that actually grows revenue: customers, go-to-market, product decisions that move the needle. Each phase of the migration delivers a stable, improved slice of the product rather than an all-or-nothing bet on a single delivery date. The business doesn't have to hold its breath while the codebase underneath it gets rebuilt.
Sources
- Strangler fig pattern - AWS Prescriptive Guidance
- The Strangler Fig Pattern: A CTO
- Debt Behind the AI Boom: A Large-Scale Empirical Study of AI-Generated Code in the Wild
- Faster Code, Deeper Debt? A Multivocal Literature Review on Technical Debt and Its Early Signs in LLM-Assisted Software Development
- councils.forbes.com
- martinfowler.com
- altersquare.medium.com


