Exchange standards
HL7 v2, HL7 v3, CDA/C-CDA, and FHIR - how clinical data moves between systems.
Sources last verified
These are the standards that move data between systems. They are optimized for messaging and documents, not for analysis: a decade of HL7 v2 messages is an audit trail, not a dataset. Turning one into the other is what the common data models are for.
Their history is unusually legible, because each generation was a reaction to the last. HL7 v2 was too loose, so v3 was made rigorous — and was so rigorous nobody implemented it. FHIR was the correction: web-native, pragmatic, and explicitly willing to leave 20% of cases to extensions.
HL7 v2
The pipe-delimited messaging standard that still carries the majority of clinical data movement inside hospitals.
- Introduced: 1987 (HL7 founded); v2.1 in 1990. Current release is v2.9, but v2.3 and v2.5.1 are what you will actually meet
- Purpose: Real-time event messaging between departmental systems — admissions, orders, results, transfers
- Encoding: Plain text, segment-per-line,
|fields,^components,~repeats - Body: Health Level Seven International
- Status today: Overwhelmingly dominant for intra-hospital integration and not going anywhere. Estimates of coverage vary, but no serious observer disputes that v2 still moves more clinical messages per day than every other standard combined
- Competing formats: FHIR is the designated successor and is winning at the API boundary, but has barely dented v2's position inside the hospital
Each message is a sequence of segments. MSH (header) is always first; the trigger event in
MSH-9 tells you what kind of message it is (ADT^A01 = patient admission, ORU^R01 = lab
result).
MSH|^~\&|EPIC|MEMORIAL|LABSYS|MEMORIAL|20260112143000||ADT^A01|MSG00001|P|2.5.1
EVN|A01|20260112143000
PID|1||10023847^^^MEMORIAL^MR||DOE^JANE^A||19850312|F|||123 MAIN ST^^BOSTON^MA^02115
PV1|1|I|ICU^301^A|||||1234567^SMITH^JOHN^^^^MD|||||||||||V0012345MSH|^~\&|LABSYS|MEMORIAL|EPIC|MEMORIAL|20260112151500||ORU^R01|MSG00002|P|2.5.1
PID|1||10023847^^^MEMORIAL^MR||DOE^JANE^A||19850312|F
OBR|1|ORD9931|RES4471|24323-8^COMPREHENSIVE METABOLIC PANEL^LN|||20260112150000
OBX|1|NM|2345-7^Glucose^LN||142|mg/dL|70-99|H|||F|||20260112150000
OBX|2|NM|2160-0^Creatinine^LN||0.9|mg/dL|0.6-1.1|N|||F|||20260112150000Note the LN in OBX-3 — that is a LOINC code. The
exchange standard carries the terminology; it does not replace it.
The hard part of v2 is not parsing, it is that the standard is a negotiating framework rather
than a specification. Z segments are locally defined, optional fields are used
inconsistently, and every interface is its own dialect. Budget for a site-specific mapping
document, always.
| Language | Package | Notes |
|---|---|---|
| Java | HAPI HL7v2 | The reference implementation. Full message model for every version, plus MLLP transport. If correctness matters, this is the one |
| Python | hl7apy | Full message model with validation against the official schemas |
| Python | hl7 | Lighter parsing plus an MLLP client. Good when you just need to read fields |
| TypeScript | simple-hl7, hl7-standard | Parse and build; no schema validation |
| Rust | hl7-parser, hl7-mllp-codec | Parsing and transport only. No message model |
| R | — | Nothing on CRAN. Parse in Python and hand over the table |
| Julia | — | Nothing in General |
| CLI | Mirth Connect | The de facto interface engine. Note the open-source repo has been quiet since 2024 following the move to a commercial license — check the licensing before you build on it |
HL7 v3 and the RIM
The attempt to put HL7 on a rigorous formal footing, via a single Reference Information Model from which all messages would be derived.
- Introduced: Development from the mid-1990s; normative editions from 2005
- Purpose: Eliminate v2's ambiguity with a model-driven, XML-based standard
- Status today: Effectively abandoned as a messaging standard. Implementation cost was prohibitive and adoption never materialized outside a few national programs
- What survived: Two things, and they matter. CDA, which is v3-derived and thriving, and the RIM's conceptual vocabulary, which shaped how the field talks about clinical data to this day
You will not build anything new on v3. It is here because you will encounter references to it and should know it is a dead end rather than a gap in your knowledge. Its failure is also the direct cause of FHIR's design philosophy.
CDA / C-CDA
The Clinical Document Architecture: an XML standard for documents — discharge summaries, care records, referral notes — rather than events.
- Introduced: CDA R1 in 2000; CDA R2 in 2005; Consolidated CDA (C-CDA) R1.1 in 2012, R2.1 in 2015
- Purpose: A persistent, human-readable, legally attestable clinical document that is also machine-parseable
- Encoding: XML, derived from the HL7 v3 RIM
- Status today: Entrenched in the US because Meaningful Use required it. The Continuity of Care Document (CCD) is the template you will meet most
- Competing formats: FHIR Documents and the
$docrefoperation are the successor, but C-CDA remains the required format for several certification criteria
The defining feature is the dual body: every section carries a human-readable narrative block and structured entries, and the two are required to agree. The narrative is what a clinician is legally attesting to; the entries are what your parser reads.
<section>
<templateId root="2.16.840.1.113883.10.20.22.2.3.1" extension="2015-08-01"/>
<code code="30954-2" codeSystem="2.16.840.1.113883.6.1" displayName="Results"/>
<title>Results</title>
<!-- Human-readable narrative: what the clinician attests to -->
<text>
<table>
<tbody>
<tr><td>Glucose</td><td>142 mg/dL</td><td>High</td></tr>
</tbody>
</table>
</text>
<!-- Structured entry: what your parser reads. Must agree with the above. -->
<entry>
<observation classCode="OBS" moodCode="EVN">
<templateId root="2.16.840.1.113883.10.20.22.4.2"/>
<code code="2345-7" codeSystem="2.16.840.1.113883.6.1" displayName="Glucose"/>
<statusCode code="completed"/>
<effectiveTime value="20260112150000"/>
<value xsi:type="PQ" value="142" unit="mg/dL"/>
<interpretationCode code="H" codeSystem="2.16.840.1.113883.5.83"/>
</observation>
</entry>
</section>Those templateId OIDs are the whole game. Conformance is defined by which templates a document
claims, and validation means checking Schematron rules per template — not merely that the XML is
well-formed. A document can be schema-valid and still wrong.
This is the weakest tooling story in the whole domain. There is no maintained, CDA-aware parsing library in any scripting language. In practice everyone writes XPath against the templates they care about.
| Language | Package | Notes |
|---|---|---|
| CLI | xmllint, Saxon | Schema validation, then Schematron for the template rules. This is the real workflow |
| Java | HL7 validator | Validates CDA as well as FHIR. MDHT, the old CDA-specific toolkit, is archived — do not start there |
| Python | lxml | Generic XML with XPath. You supply the template knowledge |
| R | xml2 | As above |
| TypeScript | bluebutton | Parses C-CDA/CCR to plain JSON. Long unmaintained, but still the shortest path to a quick read |
Beware anything on PyPI or npm whose name merely looks like a CDA library. The PyPI package
cda is "College Data Analysis" and has nothing to do with clinical documents.
FHIR
Fast Healthcare Interoperability Resources: the modern standard, and the only one being actively built on.
- Introduced: Drafted by Graham Grieve in 2011; DSTU1 2014, STU3 2017, R4 2019 (first normative content), R4B 2022, R5 in March 2023. R6 is in ballot as of September 2026
- Purpose: Web-native health data exchange — REST, JSON, OAuth — designed so that a competent web developer can be productive without a decade of HL7 background
- Encoding: JSON (dominant), XML, or Turtle
- Body: HL7 International
- Status today: Mandated in the US by the 21st Century Cures Act. Every major EHR exposes a FHIR API. This is where new work goes
- Competing formats: None with momentum. openEHR is the main alternative architecture and has real deployments in Europe, but FHIR has won the API layer
Build against R4, not R5. R5 is the current published release, but US regulation — USCDI, US Core, and the Cures Act certification criteria — is anchored to R4 (4.0.1). Real EHR endpoints serve R4. Use R5 only if you have a specific reason and control both ends.
Everything is a resource: a Patient, an Observation, a Condition. Each has a stable
identity, a URL, and a version, and resources reference each other.
{
"resourceType": "Observation",
"id": "glucose-20260112",
"status": "final",
"category": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "laboratory"
}]
}],
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "2345-7",
"display": "Glucose [Mass/volume] in Serum or Plasma"
}]
},
"subject": { "reference": "Patient/10023847" },
"effectiveDateTime": "2026-01-12T15:00:00-05:00",
"valueQuantity": {
"value": 142,
"unit": "mg/dL",
"system": "http://unitsofmeasure.org",
"code": "mg/dL"
},
"interpretation": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
"code": "H",
"display": "High"
}]
}]
}The same glucose result, in all three standards above. That is the point worth internalizing: the
LOINC code 2345-7 is constant across every one of them.
Profiles are where the real specification lives
Base FHIR is deliberately underspecified — roughly 80% of what everyone needs, with the rest left
to profiles that constrain resources for a context. US Core is the profile set that US
regulation actually requires; saying "we support FHIR" without naming a profile says almost
nothing.
SMART on FHIR and Bulk FHIR
Two extensions you will need by name:
- SMART on FHIR — the OAuth2/OpenID Connect layer that lets a third-party app launch inside an EHR with scoped access to one patient's chart. This is how EHR-embedded apps are built
- Bulk FHIR (Flat FHIR) — the
$exportoperation, returning newline-delimited JSON for a whole population rather than one patient at a time. This is the one that matters for research: it is the sanctioned route to a cohort-sized extract
# Kick off an export; returns 202 with a Content-Location to poll
GET [base]/Group/[id]/$export?_type=Patient,Observation,Condition
Accept: application/fhir+json
Prefer: respond-async
# When complete, the status endpoint returns URLs to NDJSON files, one per resource type| Language | Package | Notes |
|---|---|---|
| Java | HAPI FHIR | The reference implementation — client, server, validator, terminology. Every other library is measured against it |
| Python | fhir.resources | Pydantic models for every resource in R4/R4B/R5. The default choice for validation and typed access |
| Python | fhirpy | Async REST client with a query builder |
| Python | fhirclient | The SMART on FHIR reference client |
| Python | fhirpathpy | FHIRPath evaluation — the query language for navigating resources |
| Python | pathling | Spark-based analytics over FHIR at population scale. The right tool for Bulk FHIR output |
| R | fhircrackr | Downloads bundles and flattens them to data frames. Built for exactly the research use case; not a general-purpose client |
| TypeScript | @medplum/core | Full-featured client from an actively developed FHIR platform |
| TypeScript | fhir-kit-client, fhirpath, @types/fhir | Client, FHIRPath engine, and type definitions |
| Rust | fhir-sdk | Models and client for R4B/R5, actively maintained. Prefer it to fhirbolt, which has been quiet since 2023 |
| Julia | — | Nothing in General. Call a FHIR server over plain HTTP and parse the JSON |
| CLI | sushi | Compiles FHIR Shorthand to an implementation guide. Standard for authoring profiles |
| CLI | HL7 Validator | The official validator jar. Validates against profiles, not just structure |
| CLI | Inferno | ONC's conformance test suite. What certification is measured with |
USCDI
Not a format — a required content list. The United States Core Data for Interoperability specifies which data elements a certified EHR must be able to exchange, and US Core maps each one onto FHIR R4 profiles.
- Introduced: v1 in 2020, replacing the older Common Clinical Data Set
- Cadence: Annual. v7 was published on 23 July 2026, adding 31 data elements
- Why it matters to you: It is the floor. If a data element is in USCDI, a certified EHR is obliged to expose it via FHIR — which makes USCDI the most reliable predictor of what you can actually get out of a system
Versions accumulate rather than replace, and certification criteria lag the newest version by years, so check which version your target system is certified against rather than assuming the latest.