Nobody schedules the meeting where the legacy system becomes a legacy system. It’s just the thing that runs payroll, or handles order fulfillment, or manages licenses—and one day a new platform arrives and you need the two to talk. The old one has no REST API. The team that built it is gone. You realize you’re going to be solving this for a while.
The framing that follows—“do we rewrite or do we integrate?”—is the wrong question. A rewrite is rarely available. The business runs on the old system. Regulatory state, edge cases, eighteen years of accumulated behavior nobody has documented: you can’t just stop and rebuild. Integration it is.
What most teams don’t anticipate is that choosing to integrate isn’t the hard part. The hard part is what happens in the layer between the old system and the new one—the code that translates protocols, transforms data, handles failures, routes events from here to there. That middle layer is where projects succeed or collapse. The architectural choices you make there early will either compound in your favor or haunt your on-call rotation for years.
How you integrate legacy systems with modern platforms is a question about what you build in the middle, not what you do to the systems at either end.
The rewrite instinct is usually a symptom, not a solution
When integration projects hit trouble, teams start asking whether a rewrite would have been cleaner. Sometimes they’re right. More often, the trouble lives in the integration layer itself, and a rewrite wouldn’t fix it—you’d just have a newer system at one end with the same messy middle.
The failure patterns are recognizable: data transformations written as one-off scripts with no version history; event handling logic baked into a Lambda function that one engineer understands; error states that log to a file nobody reads; a protocol translation layer that grew from “just a quick adapter” into the most critical undocumented piece of infrastructure in the organization.
None of that is a problem with the legacy system’s age. It’s a problem with how the integration was built and operated. The legacy system was doing its job. The integration layer wasn’t doing its.
There’s a second thing the rewrite instinct underweights: how long the old system actually stays in service after the “integration phase” ends. Most legacy systems connected to modern SaaS platforms don’t go away on the timeline the project assumed. They run for another five years, handling the transaction volume nobody wanted to migrate because it was too risky, serving the product line that wasn’t a priority, persisting because a full cutover never actually happened. Whatever you build in the middle has to survive that.
The middle layer will outlive the project that created it.
What the integration layer actually needs to do

Most integration guides focus on the connection: pick an approach, wire up the endpoints, confirm data moves, ship it. That’s the prototype. What turns a prototype into something production teams can depend on is a different set of questions.
Can you debug it without logging into two separate vendor consoles? When a batch job that runs at 3 a.m. fails partway through, how long does it take you to find out? If the failure was in step four of a twelve-step pipeline, do you know what steps one through three produced—or are you starting from “something went wrong” with no more information than that?
That’s the observability question, and it’s the one integration projects almost always defer. Get the data flowing first, worry about visibility later. In practice, “later” arrives as a production incident, and the absence of traces means the incident takes four times as long to resolve.
The second question is about change. Legacy systems don’t stop changing. The upstream schema mutates. A new field appears. A format shifts from pipe-delimited to fixed-width because the upstream team made a decision you weren’t in the room for. How long does it take your integration layer to absorb that? Is there a test that would catch a schema mismatch before the 8 p.m. payroll sync?
The third is cost. Integration layers that sit between legacy systems and modern SaaS platforms tend to handle high, spiky volumes—batch exports, event bursts, sync cycles on business schedules. If your integration platform bills by execution, those spikes show up on your invoice. A workflow that handles peak load once a quarter costs less in a slow month and more in a busy one. Your infrastructure cost becomes a function of your business’s own success. That’s a bad property to have baked into load-bearing plumbing.
The integration layer’s failure modes—silent errors, undebugable pipelines, schema surprises, execution-based billing—are the actual cost of legacy connectivity. Not the systems at either end.
The architectural patterns that hold up

Three properties separate integration layers that stay maintainable from ones that accumulate debt the way the legacy system did.
Treat the integration as software. That means version control—real version control, where the workflow definition lives in your repo alongside the rest of your production code, not a JSON export someone periodically downloads to a backup folder. Branches when you need to test a schema change. A history you can read when you need to understand why a mapping decision was made six months ago. A review process for changes to the pipeline before they reach the production sync window.
First-class observability from day one. OpenTelemetry traces that cover every step of every flow, indexable by the attributes that matter: customer, record type, timestamp, error class. The ability to filter to “all payroll events for this subsidiary on Tuesday night” and get an answer—not a log file to grep. This isn’t optional infrastructure you add when things go wrong. It’s what makes the integration layer a system you can reason about instead of one you’re afraid to touch.
Isolation. The integration layer between a legacy ERP and a modern HRIS shouldn’t also be the integration layer between your CRM and your billing system, sharing state and execution context in ways that let a failure in one cascade into the other. Discrete, well-scoped workflows with clear ownership and separate failure surfaces—the same modularity you’d apply to any production service—is what makes the layer survivable when one piece needs to change.
Integration debt accrues in the same ways application debt does: missing tests, missing observability, logic in the wrong place, no clear owner. The architectural fixes are also the same.
The longer argument for why ownership of this layer matters—code, telemetry, and cost—lives in why unobservable integration stacks are the real hidden bill, if you want the full thesis before making any platform decisions.
Where the rewrite conversation actually becomes useful
None of this argues against modernization. There are real cases where a legacy system has exhausted its usefulness and the work of integration outpaces the work of replacement.
The signals that point that direction: the system has no externally reachable surface, so every integration requires a filesystem bridge or a screen scraper; the business logic it encodes is wrong, not just old, and the integration is being used to work around known failures rather than connect valid data; or the organization has actually committed resources and timeline to a migration, not just discussed it.
Short of those conditions, incremental integration with a well-built middle layer is faster, lower-risk, and more reversible than a rebuild. And if a migration eventually does happen, the integration work isn’t wasted—a well-instrumented, version-controlled integration layer gives you the test harness and observability baseline for a cutover that an undocumented point-to-point connection never could.
What this means practically
Before you pick tools for a legacy integration project, ask one question: what does this layer look like in two years, when the “integration phase” is over and it’s just infrastructure?
Is the workflow definition in version control, in a form new engineers can read and modify? Is there a trace for every run, exportable to the observability stack the team already uses? Is there a test that validates the schema contract before a change ships? And is the billing model compatible with the actual traffic patterns—no per-execution meter that scales with the business logic you’re connecting, no overage invoice because the legacy batch ran twice?
Those aren’t questions about the legacy system. They’re questions about the middle layer. Get that layer right and the legacy system is just a well-understood endpoint with a stable interface. Get it wrong and you’ve built another system you’ll eventually need to integrate around.
Koodisi is built for exactly this—workflows in Git, OpenTelemetry traces on every tier from Community onward, and pricing at $399/mo Professional with no per-execution billing and no overage invoices. If you have a legacy system that needs connecting and want to see what the middle layer looks like when it’s built to be owned, the Community tier is free and gets you to a working flow without a credit card.