Legacy system integration: when to wrap a system instead of replacing it

UX designer workshops

Wrapping a legacy system and modernizing it solve different problems, and treating them as interchangeable is what stalls most integration efforts. The real question isn't 'can we expose this data', that's almost always solvable with an integration layer.

The harder question is whether the system underneath can still change, and whether an integration layer is buying time for that change or quietly replacing the need for it. Get that distinction wrong and the integration layer itself becomes the next legacy system to untangle. This guide gives you the pattern-selection logic and the exit signals to avoid that.

TL;DR: Wrap it or replace it?

A legacy system that cannot expose data is a different problem from one that cannot change, and mixing up the two is why integration projects turn into permanent maintenance work. If your ERP can already answer the question (orders, inventory, customer flags), you need an integration layer, not a rewrite.

If it cannot answer the question because the logic itself is wrong, no facade fixes that; that legacy system needs modernization, not wrapping.

Across ERP and core-system integration engagements, we've repeatedly seen legacy data model concepts (order states, customer flags, unit-of-measure fields) surface unmodified in new service code during review.

That pattern is the signal that a thin wrapper is not enough, and the legacy system needs an anti-corruption layer between it and any modern service, not just an API on top.

The quick win: before picking a pattern, write down which of the two problems you actually have. Every option that follows (API facade, CDC, iPaaS) depends on that answer, and picking one before answering it is how a bridge quietly becomes the next legacy system nobody planned to own.

This piece works through the patterns in the order teams actually evaluate them, what each costs to run and not just to build, and the signals that tell you wrapping has stopped being temporary.

Cannot expose data vs. Cannot change: Two different problems

A legacy system that cannot expose data needs an integration layer. A legacy system that cannot change needs modernization. Confusing the two is why bridge projects turn into permanent maintenance work nobody signed up for.

The first case is more common than most integration audits admit.

The ERP already knows the order state, the customer flag, the unit-of-measure conversion: the logic is correct, the data is trustworthy, and the only real problem is that nothing outside the legacy system can reach it without going through a decade-old screen.

That is a data exchange problem that many organizations face when integrating systems across departments. An integration layer solves it cleanly, because there's nothing wrong underneath to fix.

The second case is different, and modernization vendors have an incentive to blur the line. If the business logic in the legacy system is wrong, the order state machine no longer matches how the business actually operates, or the unit-of-measure field means three different things depending on which team populated it, no facade, however well built, corrects that.

Wrapping it just moves the coupling one layer up and adds technical debt to the new platform instead of the old one.

The strangler fig pattern, named by Martin Fowler in 2004, describes replacing a legacy system's capabilities piece by piece while the original platform keeps running underneath, cut over only when each piece is proven. That's a modernization strategy, not an integration one, worth knowing before you invest in an integration layer to solve a problem it was never designed to fix.

Direct database access: The trap that looks cheapest

Direct database access is the cheapest integration pattern to build and the most expensive to unwind. A new service connects straight to the legacy database, skipping any layer in between.

It looks cheapest because there is nothing else to design. No facade, no message broker, no contract to version. A developer opens a connection, queries the ERP's order table, and ships. The bill comes due the first time that table changes shape underneath the new code.

That is schema drift: the legacy database's internal structure shifts, a column renamed, a status code repurposed, a foreign key retired, and every consumer querying it directly breaks at the same moment, with no version to fall back to and no warning it was coming.

Direct access creates tight coupling between systems that were never designed to share an interface. The new application inherits the legacy system's internal data model as if it were a published contract, only nobody ever agreed to support it as one, and the legacy team that built the schema rarely still owns it.

We've reviewed integration layers on ERP engagements where this pattern had been accumulating for years: half a dozen services querying the same order table on different, undocumented assumptions about what a given status code meant.

Direct database access is defensible in one narrow case: a short-lived reporting query against a system already scheduled for retirement, where nothing downstream depends on long-term stability.

Everywhere else, it turns an undocumented legacy schema into a second, silent API surface nobody chose to maintain, and the modern applications built on top of it inherit that risk without ever seeing it.

When an API facade is the right next step

An API facade earns its cost when the legacy system can already answer the question but can't answer it in a shape anything modern wants to consume.

That's the reframe worth sitting with: a system that can't expose data and a system that can't change are different diagnoses, and only the second needs a modernization program. Most ERPs fall into the first category, the data is there, the schema is just decades old.

An API facade is a thin service you build and own that sits in front of the legacy system and translates its interface into something a new application can call without knowing the legacy schema exists. It doesn't touch the legacy code, maintaining security and stability across your existing systems. It wraps it.

Don't confuse this with an API gateway, which uses different underlying technologies for request routing and management. A gateway is infrastructure, routing, auth, rate limiting, request logging, sitting in front of one or many backends, facade included. The facade is the translation logic; the gateway is the traffic layer around it.

Teams that skip the facade and put a bare gateway in front of raw ERP endpoints just get direct database access with better logging.

Build cost is moderate: one service, one team, a defined contract. Run cost is the part vendor integration content skips: someone has to own the facade when the ERP vendor ships a schema change, and that ownership tends to drift once the original builders move on.

An API facade is wrong when the legacy data model itself is the problem: when order states, flags, and unit-of-measure fields would otherwise leak straight through into new service code. That's the anti-corruption layer's job, not the facade's.

What is an anti-corruption layer, and when do you need one?

An anti-corruption layer is a translation boundary that keeps a legacy system's data model out of new code. It converts legacy concepts into a domain model that fits what you are building. Martin Fowler's bliki entry defines it this way: a layer that translates between two domain models so that changes on one side do not leak into the other.

The legacy system does not need to be badly built to justify one. It only needs a data model that does not match the shape your new services want.

ERPs are the clearest example: order states, customer flags, and unit-of-measure fields carry decades of business rules baked into cryptic codes, and none of that belongs in a clean domain model.

The signal that you need an anti-corruption layer shows up in code review, not architecture diagrams. When a legacy field name or status code starts appearing unmodified in new service code, and a reviewer has to ask what it means, that is coupling arriving uninvited. Left unchecked, every consumer downstream ends up decoding the same legacy quirks independently.

Building the layer costs real engineering time: a set of translation classes, tests that pin the mapping, and a place to put business logic that used to live implicitly in the old schema. The payoff is that legacy changes stay contained. When the ERP vendor renames a status code or adds a value, one translation layer absorbs it instead of every downstream consumer.

Skip the layer and you get an API facade wearing a costume: it looks decoupled but every consumer still speaks the legacy system's dialect, and the cost of that coupling shows up later, at the worst possible time.

When event streaming or CDC beats an API facade

Event streaming and change data capture (CDC) beat an API facade when consumers need data continuously rather than on request. The second trigger is load: polling a legacy system puts pressure it was never built for.

CDC reads a legacy database's transaction log and turns each row change into an event, without touching the legacy application code at all. An event streaming layer then pushes those events onto a message queue or broker, so any number of new services can consume the same change without asking the legacy system anything directly.

Gregor Hohpe and Bobby Woolf's Enterprise Integration frame this as decoupling producers from consumers through an intermediary channel, which is exactly the property that makes it fit here: the legacy system stops being queried and starts being observed.

Build cost is moderate: a CDC connector against the transaction log, an event schema, and contract tests that fail loudly if the legacy schema drifts underneath.

Run cost is the part vendor pitches skip: broker infrastructure, consumer lag monitoring, and schema evolution management that grows with the number of consumers, not the number of endpoints. AWS's guidance on event-driven architecture is worth reading before committing, because ordering and delivery guarantees are where teams get burned.

The failure mode: a legacy column gets renamed or repurposed and the connector keeps running, quietly emitting garbage until a consumer notices.

This pattern is wrong when you have one consumer needing a synchronous answer, an API facade is simpler and cheaper there, or when the legacy database exposes no usable log at all, in which case scheduled batch export is the honest fallback, not real streaming.

When a full iPaaS actually pays for its license

A full iPaaS platform earns its licence at roughly a dozen systems exchanging data across different formats, cadences and protocols. It does not earn it when the first two systems need to talk. Below that count, an API facade or a CDC pipeline is cheaper to build and cheaper to run.

The economics flip because iPaaS platforms price on connectors and data volume, not on complexity solved. Below the threshold you are paying for orchestration you do not need. Above it, hand-rolling point-to-point integration between a dozen systems produces the exact tangle iPaaS exists to prevent, n² connections, each one a custom failure mode.

This is also where the Enterprise Service Bus's history is worth remembering. The ESB pattern, described in Gregor Hohpe and Bobby Woolf's Enterprise Integration, promised one message bus for all system-to-system traffic and, in practice, often became a second legacy system nobody wanted to own.

Modern iPaaS platforms inherit that risk in a new shape: vendor lock-in through proprietary connectors, transformation logic buried in a platform's own DSL, and a bill that scales with endpoint count independent of actual usage, a pattern we see repeatedly on ERP-heavy estates where the platform's per-connector pricing keeps climbing after the integration work itself has stopped changing.

IPaaS is the right call for a genuinely multi-system estate: ERP, CRM, warehouse management, and a handful of SaaS tools all exchanging data on different schedules. It is the wrong call as a default first move, and the wrong call to buy before the endpoint count justifies the license.

What an integration layer costs to run

What an integration layer costs to run rarely shows up in the business case that got it approved.

Build cost is a project with a start and end date. Run cost is compute, licensing, and the one engineer who still remembers why the mapping layer does something odd with unit-of-measure fields, and that cost compounds differently for every pattern above.

IPaaS is the clearest case. Licensing scales with connector and endpoint count, not with transaction volume or usage. Add a fifth system to the estate and the bill jumps whether that system pushes ten records a day or ten million. We have seen integration budgets creep every year without the business getting materially more data flow for it, purely because someone connected another endpoint.

A direct database access hook or an API facade doesn't have this problem, it costs almost nothing to run until the day the legacy schema changes underneath it, at which point the cost lands as an outage instead of a bill.

The deeper run cost is organizational, requiring investment in automation infrastructure and process redesign. Integration layers routinely outlive the team that built them. Five years on, nobody on staff can explain the retry logic or why a particular event stream drops duplicate order-state messages, and every change to the legacy system on the other side becomes a guess rather than a diagnosis.

That is technical debt with a specific shape: not messy code, but a system nobody can safely touch. iPaaS platforms typically price per connector rather than per call, so the licence grows with the number of systems you attach, not with how much traffic actually flows between them.

Keeping the integration layer from becoming the next legacy system

An integration layer becomes the next legacy system when three things are true at once: nobody owns it, nothing tests it against the system it wraps, and no one wrote down when it should die. All three are fixable at build time, and cost almost nothing next to the price of discovering them later.

Contract testing is the first safeguard, and it has to run against the legacy system itself, not just against the new service's assumptions about it. Legacy systems change quietly: a patched ERP module, a renamed status code, an order state a vendor upgrade added without telling anyone.

A contract test suite pinned to the anti-corruption layer's mapping catches that drift the day it happens, not the week a customer notices a silent data mismatch in production.

Second, name an owner for the integration layer who is distinct from whoever owns the legacy system and whoever owns the new platform. Ownerless integration layers are exactly the ones we see outlive the engineer who understood their failure modes across ERP and core-system integration reviews.

Third, write a retirement condition into the design doc, not the backlog. "Tear down when the ERP migration completes" or "tear down when consumers read from the event stream directly" is a real condition. No condition means you built a permanent system under a temporary name, and Fowler's strangler fig pattern offers no guidance on removing scaffolding nobody decided to remove.

The exit signal to watch for: the integration layer develops its own release cycle, drifting from both systems it connects, and the mapping logic grows every quarter instead of shrinking. At that point the modernization decision is back on the table.

Exit signals: When wrapping has stopped being a bridge

Wrapping has stopped working when the system underneath moves from "cannot expose data" to "cannot change". That is the problem a wrapper was never built to solve. Four signals tell us that shift has happened.

One: the anti-corruption layer's translation rules grow faster than the legacy system's actual business logic, meaning the team is now maintaining two data models instead of one. Two: nobody on the current team can explain the legacy system's failure modes, only the wrapper's: the original owner left, and the technical debt inside the core system is now invisible by default, not by design.

Three: the legacy system's vendor has stopped patching it, so every new integration point widens an unpatched attack surface rather than isolating one. Four: the run cost of the integration layer, on-call load, contract-test maintenance, iPaaS licence, now exceeds what replatforming would cost amortized over three years.

Taken together, these signals often surface during a broader enterprise software development effort, where legacy constraints must be weighed against new architecture and compliance requirements.

Any one of these on its own is manageable. Two or more together mean the wrapper has quietly become the legacy system, and the honest move is to reopen the modernization decision rather than add a fifth pattern on top. Our 7 Rs framework is the right starting point for that conversation once wrapping stops paying for itself.

If the legacy system in question is an ecommerce platform, our guide to modernizing a legacy ecommerce platform lays out the strategy, roadmap, and risk trade-offs in more detail.

FAQ: Legacy system integration

What is legacy system integration?

Legacy system integration connects an older legacy system, such as an ERP platform, to newer applications without rewriting the system underneath. It relies on patterns like an API facade, an anti-corruption layer, or event streaming to expose data and business logic on the legacy system's own terms. Get the pattern wrong and every new application ends up coupled to the old schema. These same integration patterns matter even more once AI enters the picture, since integrating AI into that environment demands the same careful handling of legacy data and business logic.

How does legacy system integration work?

Legacy system integration works by inserting a layer between the legacy system and modern consumers that translates data formats, protocols, or timing so neither side has to change. Common mechanics include change data capture reading database logs, or an API facade wrapping legacy calls in a modern contract. The layer, not the legacy system, absorbs future change. For teams weighing whether integration alone is enough, a broader modernization framework can help determine when wrapping should give way to deeper transformation.

How do I integrate a legacy system with an API?

Build an API facade that wraps the legacy system's existing interfaces in a modern REST or GraphQL contract, translating requests and responses at the boundary. Contract tests run against the legacy system itself, not just the facade, catch breakage the moment the underlying system changes. This only works if the legacy system can already expose the fields the new application needs.

What is an anti-corruption layer?

An anti-corruption layer is a translation boundary that stops a legacy system's data model leaking into new code. The term comes from Eric Evans's Domain-Driven Design. It maps legacy concepts onto a clean domain model on the new side. Build one the moment legacy fields start surfacing unmodified in code review comments.

Should I integrate or replace a legacy system?

Integrate when the legacy system's problem is that it cannot expose data; replace or modernize when the problem is that it cannot change. A wrapper solves the first cleanly but leaves brittle logic, scaling limits, and stale platforms untouched underneath. Our guide to the 7 Rs of legacy modernization walks through the replace-side decision in detail. If the underlying platform itself is the constraint, our replatforming and modernization services can help you plan the transition without disrupting the business.

How much does legacy system integration cost to run?

Run cost is the part most integration content skips. An anti-corruption layer or API facade needs a named owner, monitoring, and contract tests maintained against every legacy system release. iPaaS licences typically scale with endpoint count rather than actual usage, so cost climbs even when traffic on the integrated systems stays flat. Budget for ongoing maintenance from day one, not just the initial build.

Working out whether to wrap or replace

Most estates need both. The question is which systems get an integration layer that buys years, and which ones have to change underneath — and answering it needs a dependency map before it needs a roadmap.

Our team scopes that assessment against the systems you actually run, then sequences the work so nothing is rewritten before it needs to be. Talk to us about your estate before committing budget to either path.

We're Netguru

At Netguru we specialize in designing, building, shipping and scaling beautiful, usable products with blazing-fast efficiency.

Let's talk business