Insights / Splitting a monolith without rewriting it: the API contract is the seam

Splitting a monolith without rewriting it: the API contract is the seam

You don't break up a monolith by choosing a new language. You break it up by finding the seam — and the seam is the API contract. A field guide to a split that ships in stages.

Published

May 2026

Length

7 min read

Topics

Architecture · Modernization

Every monolith eventually gets the same memo: it's time for a rewrite. A new language, a new framework, a clean repository, eighteen months on the calendar. The memo is almost always wrong — not because the monolith is fine, but because the rewrite is a bet you usually lose.

The rewrite is a bet you usually lose

A full rewrite asks the business to fund two systems at once: the one earning revenue and the one that might replace it. For the entire build, you ship nothing. Every feature the old system gains is a feature the new one now also has to gain. The finish line moves at the same speed you do.

This isn't a new observation. Joel Spolsky called the ground-up rewrite "the single worst strategic mistake that any software company can make" in 2000, writing about Netscape — which spent three years rewriting a browser while its market share evaporated, shipping nothing the whole time. The essay is a quarter-century old and still describes a meeting happening somewhere next Tuesday.

Worse, you've converted a known quantity into an unknown one. The monolith's behavior — including its undocumented behavior, the quiet special cases ten years of production taught it — is a specification you threw away. Most rewrites discover that specification the hard way, in incidents.

Find the seam

You don't break up a monolith by choosing a new language. You break it up by finding the seam — and the seam is the API contract.

A contract is a boundary you can freeze. Once two parts of a system communicate only through a stable, documented interface — an HTTP API, a message schema, a well-defined function signature — you can change either side without touching the other. The contract is the part that has to hold still. Everything behind it is free to move.

In practice you rarely invent the seam; you discover it. Most monoliths already have one half-formed — the service layer everything routes through, the repository classes in front of the database, the one controller every integration hits. The work isn't drawing a line on a whiteboard. It's taking the boundary the code already leans on, making it explicit, documenting it, and then enforcing it — no more side doors.

The language behind a contract is an implementation detail. The contract itself is the architecture.

The pattern has a name

What I'm describing is the strangler fig, Martin Fowler's name for growing a new system around the edges of an old one — small additions, built separately from the legacy code, moving behavior across piece by piece until the old system can be switched off. Fowler's argument for it is the same as mine: investment and returns arrive gradually and visibly, and frequent releases let you monitor progress carefully instead of discovering failure at the end.

The Azure Architecture Center's write-up adds the mechanics: a façade intercepts requests and routes each one to either the legacy system or the new component, shifting traffic over as pieces migrate, until the legacy side has no callers left. Two of its cautions are worth taking seriously, because I've watched both bite. The façade must not become a single point of failure or a bottleneck — you've added a hop to every request, so treat it as production infrastructure, not scaffolding. And plan for the awkward middle, when the new system still needs unmigrated legacy functionality and vice versa; an anti-corruption layer between them keeps ten years of legacy semantics from leaking into your new code and quietly becoming its design.

Carve in stages, each one shipping

With the seam identified, modernization becomes a sequence of small, reversible moves instead of one large irreversible one. Stand up the new component behind the contract. Route a slice of traffic to it. Watch it. Route more. Retire the old path only when the new one has earned it.

The discipline that makes this work: every release reaches production. Not a staging branch, not a demo — production. If a stage can't ship on its own, it's too big; cut it smaller. A modernization that delivers value in week three is a modernization the business will let you finish.

Two recent projects of mine, at very different scales, ran on exactly this discipline.

The small one is this site. It's an ASP.NET Core application — MVC, EF Core, an admin area doing CRUD over all the content. When it needed a serious revamp, I had two worked-up proposals on the table: revamp in place, or rebuild the public surface as a static front end fed by a .NET API. I shipped the in-place revamp first, because it could ship first. Then I leaned out the database and added a key-protected content API so an AI agent could publish drafts. That API is the seam. The static-front-end option didn't get rejected — it got deferred at zero cost, because the admin and the data layer now sit behind a contract that doesn't care what renders the HTML. If the rebuild ever earns its place, it's a stage, not a rewrite.

The large one is a master-data platform I designed for an enterprise client. The recommendation that survived every architecture review: start as a modular monolith — one deployable, one database — but draw the module boundaries exactly where the service boundaries would be, so any module can be peeled into its own service when the scale numbers exist rather than when the diagram looks nicer. The seam is drawn on day one. The split is deferred until it's earned. That's the same pattern at enterprise size: the contract is the architecture; the deployment topology is a decision you get to keep making.

Keep the contract honest

A frozen contract only works if everyone agrees on what "frozen" means, and the best definition I know comes from consumer-driven contracts: the contract that matters is the set of things consumers actually use, not everything the provider happens to expose. Freeze that, and you keep far more freedom than you expected — fields nobody reads can change; endpoints nobody calls can go.

In practice this means two habits. Contract tests on both sides of the seam, run in CI, so a break is a failed build and not a production incident. And additive evolution while the migration is live: new endpoints and optional fields are cheap; renaming or removing anything a consumer touches is a breaking change to a boundary whose entire job is to hold still. When my content API later grew update operations for the agent, they landed as new tools and optional fields — the existing consumers never noticed.

What the contract buys you

Three things, all of them valuable. Language independence — the public surface of a site can be rebuilt in a static framework while the admin and the data layer stay on the runtime they were always good at. Parallel work — once the contract is fixed, two people (or two teams, or a person and an AI agent) can build the two sides at once, because neither can break the other without breaking the contract first. Reversibility — if a stage goes wrong, you roll back one component, not one year.

When the rewrite really is right

Honesty requires the other side. The strangler fig is a pattern, not a law, and the Azure guidance is usefully blunt about where it doesn't fit: when requests to the back-end can't be intercepted, when you can't modify the legacy system's source, when you need the old system decommissioned fast — and when the system is small enough that wholesale replacement is simply easier. Herb Caudill's survey of six real-world rewrites reaches a compatible verdict: the rewrites that worked were mostly new products built alongside a still-earning old one, or small systems with well-understood specs — not in-place big bangs on large living systems.

So run the test before reaching for the pattern. If the whole thing could be rebuilt and verified in a few weeks, rewrite it and move on. Strangler figs are for trees, not shrubs.

The honest version

Staged modernization is slower to feel heroic and faster to actually land. It won't give you the satisfaction of a green-field repository. It will give you a system that was never down, a team that never lost the thread, and a business that watched the value arrive in increments it could trust.

The short version: find the seam. Freeze the contract — the part consumers actually use. Carve in stages. Ship every one.