DEV Community

Cover image for FHIR at the Boundary, or FHIR All the Way Down?
James Sanderson
James Sanderson

Posted on

FHIR at the Boundary, or FHIR All the Way Down?

If you are building clinical software, FHIR has effectively won as the exchange standard. That question is settled. The open question is architectural: do you translate to FHIR at your system boundary, or do you store FHIR resources natively?

hero

This gets decided early, usually implicitly, and it is expensive to revisit.

Posture one: FHIR at the boundary

Keep your own internal data model. Translate to and from FHIR resources at the API edge.

This is the common choice, and for most teams it is correct — particularly if you have an existing schema. Your internal model can be shaped for the transactional workload you actually run: the write patterns of a busy clinic, the queries your UI makes, the reporting your customers need. FHIR resources are shaped for exchange, which is a different optimisation target.

The failure mode is translation fidelity, and it degrades quietly.

Your internal model and the FHIR representation drift apart. Someone adds a field to support a customer request. It has no natural FHIR mapping, so it goes into an extension — or, more often, it silently does not get exported at all. Repeat for three years and your FHIR output is a lossy projection of your real data, technically conformant and clinically incomplete.

The mitigation is unglamorous and effective: build the translation layer early, and run conformance testing continuously rather than as a pre-launch activity. Teams that defer FHIR to "phase two" find their internal model has drifted somewhere that maps badly, and the reconciliation work is far larger than it would have been on day one.

Put conformance validation in CI. Treat a mapping gap as a failing test, not a backlog item.

Posture two: FHIR native

Store FHIR resources as your primary representation.

This removes the entire class of translation-fidelity bugs. What you store is what you publish. There is no drift because there is no second model.

The cost is that you are running your transactional system on a data model designed for exchange. FHIR resources are deeply nested, heavily polymorphic, and generous with optionality — because they have to represent every variation across every health system in the world. That generality is a liability when you are trying to enforce your own invariants. Fields that must always be present in your domain are optional in the spec. Relationships that are one-to-one for you are one-to-many in the resource. Your query patterns cut across resource boundaries in ways the model does not anticipate.

Teams that go native often end up building a constrained profile over the spec and enforcing it in application code — which is reasonable, and is also most of the work you were avoiding by not having a separate internal model.

Native storage makes sense when exchange genuinely is your primary workload: aggregation platforms, health information exchanges, products whose main job is moving records between organisations. For a system where clinicians work all day, boundary translation is usually the better trade.

alt

The part that bites either way: identity

Whichever posture you pick, patient identity matching is the problem that consumes more engineering time than anyone budgets.

There is no national patient identifier in the US. When a record arrives from another organisation, you are matching probabilistically on demographics — name, date of birth, address, phone — all of which are entered inconsistently, change over time, and are frequently wrong.

Both error directions are bad, asymmetrically:

  • False match — you merge two people's records. This is a patient safety event. Someone's allergy list now contains another person's data.
  • False non-match — you create a duplicate. Clinically safer, operationally corrosive, and duplicates breed silently until someone is looking at one of three partial records for the same person without knowing the others exist.

You cannot tune this away. What you can do is design for reversibility: never physically merge, always maintain a link with the evidence that supported it, and make unmerging a supported operation rather than a database repair. Teams that implement merge as a destructive operation discover the problem the first time a match is wrong, at which point the original records no longer exist separately.

Reconciliation is not deduplication

Related but distinct, and often conflated.

An incoming record says the patient takes 10mg of something. Your record says 20mg. Neither is obviously stale. What do you do?

The wrong answers are: overwrite (you destroyed clinical information), ignore (you are now knowingly out of date), or auto-merge by timestamp (timestamps in health data reflect when something was recorded, which can be months after it was true).

The workable pattern keeps both, attributes each to its source, and surfaces the conflict to a clinician at the point where it matters. That means your schema needs to represent multiple concurrent assertions about the same clinical fact — which is a very different data model from one row per medication.

This is where provenance stops being a nice-to-have. Every clinical fact needs source, assertion time, and confirmation status. Systems that model data as simply present or absent cannot represent a disagreement, so they have to resolve it silently — and silent resolution of clinical disagreement is exactly what you do not want.

What this means for AI features

The same provenance requirement is what makes AI-generated documentation safe to accept.

Ambient documentation systems draft notes and extract structured facts — diagnoses, medication changes, orders. To accept those writes, the record must attribute them, mark them as machine-generated pending confirmation, and keep them distinguishable from clinician-asserted facts permanently, at every point they surface in the UI.

If you have already built provenance for reconciliation, you get this nearly for free. If you have not, the AI feature requires a schema migration that touches every table and every read path.

Which is a reasonable argument for building it before you need it.

Full guide, including certification scope, migration sequencing and build-versus-extend: EHR vs EMR: What the Difference Means for Your Build. More on the integration side in LLM integration.

Frequently Asked Questions

Should FHIR be the native storage model or a boundary translation?

Boundary translation for most systems where clinicians work all day, because FHIR resources are optimised for exchange rather than transactional workloads. Native storage suits products whose primary job is moving records between organisations, such as aggregation platforms and health information exchanges.

What is the risk of treating FHIR as a boundary layer?

Translation drift. Fields added to the internal model over time have no natural FHIR mapping and quietly fail to export, so the published output becomes a lossy projection — technically conformant while clinically incomplete. Continuous conformance testing in CI is the mitigation.

Why is patient identity matching so difficult?

Because there is no national patient identifier in the US, so matching is probabilistic against demographics that are inconsistently entered, change over time and are often wrong. False matches are patient safety events and false non-matches create duplicates that multiply silently.

How should record merges be implemented?

Reversibly. Never physically merge; maintain a link plus the evidence supporting it and make unmerging a first-class operation. Destructive merges make the inevitable incorrect match unrecoverable, because the original separate records no longer exist.

How should conflicting clinical data be reconciled?

Keep both assertions, attribute each to its source, and surface the conflict to a clinician where it matters. Overwriting destroys information, ignoring leaves you knowingly stale, and resolving by timestamp is unreliable because recording time often differs from when the fact was true.

What does provenance require in the schema?

Every clinical fact needs its source, assertion time, confidence and confirmation status. This is what makes reconciliation representable and is also the precondition for safely accepting AI-generated documentation, since machine drafts must stay distinguishable from clinician assertions.

Top comments (0)