Rounds & Square Pegs
Explainer

HL7 v2 vs FHIR, actually

6 min read

You will hear both terms in your first month and nobody will stop to define either one. Here is the whole picture, in the order you will actually encounter it.

HL7 v2 came first, and it is still everywhere

HL7 Version 2 is a messaging standard from the late 1980s. It moves data between systems as pipe-delimited text segments. An ADT message tells a downstream system a patient was admitted. An ORU message carries a lab result. Every major EHR still speaks it, mostly for interfaces between systems that predate the web.

It is not pretty, and it does not need to be. It is stable, well understood by every integration engineer who has touched a hospital network, and it is not going anywhere in your career.

Where v2 shows up in a real org

In most hospitals, v2 is the plumbing you never see until something breaks. Typical touchpoints:

  • ADT feeds from the EHR to the lab, radiology, pharmacy, and billing systems. When a patient is admitted, transferred, or discharged, an ADT message propagates that fact downstream.
  • Lab and imaging results returning to the chart as ORU messages. The result you see in Epic or Cerner often arrived as a pipe-delimited string hours earlier.
  • Interface engines (Rhapsody, Mirth, Cloverleaf, and similar) sitting between systems, translating, routing, and occasionally mangling v2 messages at 2 a.m.
  • Legacy departmental systems that never got a modern API layer. The blood bank, the old LIS, the homegrown scheduling tool from 2003: still v2.

If someone mentions MLLP, an interface engine, or a pipe-delimited message, they mean v2. MLLP is the transport wrapper: a start block, the message, an end block, sent over TCP. It is unglamorous and it works.

A tiny v2 example

Here is a simplified ADT^A01 (patient admit) message. The pipes and carets are the syntax; do not memorise the fields, just recognise the shape:

MSH|^~\&|REG|HOSPITAL|LAB|HOSPITAL|20250717143000||ADT^A01|MSG00001|P|2.5
EVN|A01|20250717143000
PID|1||123456^^^HOSPITAL^MR||Smith^Jane||19850312|F
PV1|1|I|3W^301^A|U

MSH is the header (who sent it, when, what type). PID is patient demographics. PV1 is the visit (inpatient, ward, bed). Real messages are longer, messier, and full of local conventions your site invented fifteen years ago and documented nowhere.

FHIR is the API version

Fast Healthcare Interoperability Resources represents the same kinds of data (patients, observations, medications) as JSON or XML resources, exchanged over standard web APIs. If you have used any REST API, FHIR will look familiar almost immediately: GET /Patient/123, POST /Observation.

FHIR is what new interoperability work is built on, and it is the standard behind most of what you will hear called "patient access APIs" under recent regulation.

Where FHIR shows up in a real org

FHIR tends to appear anywhere someone said "we need an API" in the last five years:

  • Patient-facing apps pulling records via SMART on FHIR (MyChart integrations, third-party apps the patient authorises).
  • Population health and analytics platforms ingesting structured resources instead of parsing v2.
  • Greenfield integrations between the EHR and a new vendor product: prior auth tools, remote monitoring platforms, AI documentation vendors.
  • Research and quality reporting where a defined resource model beats reverse-engineering pipe positions.

If someone mentions a resource, an endpoint, a CapabilityStatement, or a SMART on FHIR app, they mean FHIR.

A tiny FHIR example

The same patient admit, expressed as a FHIR Patient resource (truncated):

{
  "resourceType": "Patient",
  "id": "123456",
  "identifier": [{
    "system": "urn:hospital:mrn",
    "value": "123456"
  }],
  "name": [{ "family": "Smith", "given": ["Jane"] }],
  "birthDate": "1985-03-12",
  "gender": "female"
}

You fetch it with HTTP. You get JSON back. You can read it without a segment dictionary open on your second monitor. That is the appeal, and also why people assume it replaces v2 overnight. It does not.

Why both coexist (and will for years)

Most organisations run both standards simultaneously, often through the same interface engine translating between them. The EHR still emits v2 ADT feeds because twelve downstream systems depend on them. The same EHR also exposes FHIR endpoints because regulators and new vendors require them.

This is not a failure of planning. It is what migration looks like in an environment where downtime costs lives and reverting a bad interface takes six months of committee meetings.

You hear...Likely standardTypical context
Interface engine, MLLP, ADT feedHL7 v2Core hospital plumbing
Resource, endpoint, SMART appFHIRNew integrations, patient access
"We are FHIR-native"Probably bothMarketing and reality diverge

Practical implications for your work

You do not need to become an integration engineer. You need to know enough to ask useful questions and spot category errors.

If you are on a clinical informatics or operations project: v2 is still what moves census, orders, and results between systems. When someone says "the ADT feed is down," they mean patients may not appear in downstream systems until it is fixed. That is operational, not academic.

If you are on a digital health or patient engagement project: FHIR is the vocabulary. Learn what resources matter for your use case (Patient, Encounter, Observation, MedicationRequest are the usual starting set).

If you are evaluating a vendor: Ask which standard they actually implement, not which logo they put on the slide deck. "FHIR-compliant" can mean a read-only Patient endpoint and nothing else.

If you are writing requirements: Be specific about direction (inbound vs outbound), trigger events (every admit vs scheduled batch), and error handling (what happens when the message fails validation). v2 and FHIR fail differently, but both fail loudly at the worst possible moment.

Before the integration meeting, answer these three

  1. Which standard is in scope for this interface, and is translation involved? If the answer is "both," ask who owns the mapping and where it is documented.
  2. What event triggers the message, and what is the expected latency? Real-time ADT is not the same as a nightly batch of Observations. Clinical workflows depend on the difference.
  3. What does the receiving system do when validation fails? Silent drop, error queue, or page to on-call: you want this written down before go-live, not discovered in production.

Those three questions will mark you as someone who has been in the room before, even if you have not. The rest is detail you can look up after the meeting.