You can put FHIR in front of almost any legacy EHR, but doing so does not make the underlying data interoperable — it makes it well-formed. The common pattern is a FHIR facade: an API layer that accepts standard FHIR requests and translates them into whatever the legacy system actually speaks, usually a database, a v2 feed or a proprietary API. That works well when the legacy data is complete and consistently coded, and it fails in four predictable ways when it is not. Local code sets have to be mapped to standard terminologies before an Observation means anything to the consumer. Patient identity has to resolve to something stable, or every response is about a different person. Fields the FHIR resource requires may simply not exist in the source. And a facade that translates on every request inherits the legacy system’s performance ceiling. Fix the data problems first; the facade is the easy part.

FHIR Is an Interface Standard, Not a Data Fix

I want to state the thesis plainly and early, because it’s a genuinely contrarian position against a lot of vendor marketing that treats FHIR as the answer to legacy interoperability by default. It isn’t. FHIR standardizes how data is requested and shaped in the response. It says nothing about whether the data underneath was ever complete, correctly coded, or attached to a stable patient identity. Wrapping a legacy system in FHIR gets you a well-formed response — it does not get you a trustworthy one, unless the legacy data was already trustworthy to begin with.

The FHIR Facade Pattern

The typical architecture here is a facade: a FHIR-conformant API layer sitting in front of the legacy system, translating standard FHIR requests into whatever that system actually understands underneath — a proprietary database schema, an HL7 v2 feed, a vendor-specific API. It’s attractive for an obvious reason: it lets a legacy system participate in a modern FHIR-based ecosystem without a full platform migration. That’s a legitimate goal. Where it goes wrong is when a facade gets treated as a data-quality solution rather than what it actually is — a translation layer.

Failure Mode 1 — Terminology

This is the highest-value technical section to understand, because it’s the failure mode that produces responses that look correct and aren’t. A legacy system frequently stores clinical concepts in local, homegrown codes rather than standard terminologies — LOINC for lab and clinical observations, SNOMED CT for clinical findings and procedures, RxNorm for medications. A facade that returns an Observation carrying a local code instead of a mapped LOINC code is technically valid FHIR and functionally useless to any consumer expecting standard terminology — they can’t interpret what the value actually means. Mapping local codes to standard terminologies has to happen somewhere in the pipeline, and if it isn’t happening in the facade, it isn’t happening at all.

Failure Mode 2 — Patient Identity

A facade is only as good as its ability to resolve who a given record is actually about. Legacy systems accumulated over years frequently carry duplicate patient records, merges that didn’t fully propagate, and no stable identifier that a modern consumer can rely on. A FHIR facade that hasn’t solved identity resolution first can return a well-formed Patient resource that’s quietly attached to the wrong medical history — which is a far more dangerous failure than an obviously broken response, because nothing about it looks wrong from the outside.

Failure Mode 3 — Data That Simply Isn’t There

FHIR resources have required elements, and a legacy system frequently doesn’t capture the equivalent field at all — it was never part of that system’s original data model. The honest options when this happens: omit the field and accept a technically incomplete resource, extend your data model to accommodate what’s genuinely missing, or invest in fixing it upstream in the legacy source. What you cannot honestly do is fabricate a value to satisfy the schema — that’s worse than an incomplete response, because it presents invented data as real.

Failure Mode 4 — Performance

A facade that translates on every single request inherits whatever performance ceiling the legacy system underneath already has — and legacy systems built decades ago were rarely designed for the query patterns a modern FHIR consumer expects. Caching strategies help for read-heavy workloads; for anything at real volume, materializing data into a proper FHIR-native store ahead of time, rather than translating live on every call, is frequently the only way to get acceptable performance.

When a Facade Is the Right Call Anyway

I want to be balanced here, because everything above could read as an argument against facades entirely, and that’s not the position. A facade is a genuinely good architecture choice for read-only reporting use cases where the data’s existing quality is acceptable, as a bridge during a longer migration to a modern platform, or simply to buy time while a bigger data-quality investment gets planned and funded. The argument isn’t against facades — it’s against assuming one is automatically sufficient without checking the four failure modes above first.

The Alternative: Fix It at the Source

Sometimes the right call is investing in the legacy data itself rather than building an ever-more-sophisticated translation layer on top of it — real terminology mapping projects, identity-resolution cleanup, filling genuine data gaps. This is a bigger, slower investment than standing up a facade, and it’s the right one when the legacy system is going to be a load-bearing part of your architecture for years rather than something you’re migrating away from soon. It also directly informs the broader interoperability question I go through in what actually makes EHR systems interoperable — which argues that interoperability is a property of the deployment’s data quality and standards adoption together, not either one alone.

Next Steps

If you’re evaluating whether to put FHIR in front of a legacy EHR, run the four failure modes above against your actual data before you architect anything — terminology, identity, missing fields, and performance. A facade genuinely solves the interface problem; it doesn’t solve the data problem underneath it, and pretending otherwise is how a well-formed integration ships broken data at scale. If you want a second opinion on which side of that line your legacy system falls on, talk to our team — we’d rather help you scope the real fix than build a translation layer that quietly inherits the problems it was meant to hide.