Why HL7 v2 to FHIR Migration Matters
HL7 v2.x has been the backbone of healthcare interoperability since the late 1980s. Hundreds of thousands of hospital interfaces worldwide still exchange ADT, ORU, ORM, and MDM messages over MLLP connections. Yet the industry is steadily shifting to FHIR R4 — driven by US federal regulations (CMS and ONC interoperability rules), SMART on FHIR app ecosystems, and cloud EHR platforms that natively speak REST + JSON. Migration projects must bridge these two worlds: preserving the clinical semantics of existing v2 messages while expressing them in FHIR resource graphs.
The Core Mapping Challenge
HL7 v2 and FHIR represent clinical information very differently. A v2 ADT^A01 message encodes a patient admission in a flat, pipe-delimited structure with segment-level relationships (PID → patient data, PV1 → visit data, EVN → event metadata). FHIR R4 represents the same event as a graph of linked resources: a Patient resource referenced by an Encounter resource, with contained or standalone Location and Practitioner resources. The mapping is conceptually straightforward but operationally complex — every component field in a v2 XPN, XCN, CX, or PL data type must be decomposed and reassembled into the right FHIR datatype.
ADT to Patient and Encounter
The most common migration task is converting ADT^A01 (admit) and ADT^A03 (discharge) messages. The PID segment maps to a FHIR Patient: PID-3 (CX list) becomes Patient.identifier, PID-5 (XPN) becomes Patient.name with family and given components, PID-8 becomes Patient.gender using the administrative-gender vocabulary, and PID-11 (XAD) becomes Patient.address. The PV1 segment maps to a FHIR Encounter: PV1-2 (Patient Class) maps to Encounter.class using the v3 ActCode system, PV1-7 (XCN) maps to Encounter.participant (attender), PV1-19 becomes Encounter.identifier, and PV1-44/PV1-45 become Encounter.period.start and .end.
ORU to DiagnosticReport and Observations
ORU^R01 messages carry laboratory, radiology, and clinical observation results. The OBR segment maps to a FHIR DiagnosticReport: OBR-4 (Universal Service ID, CWE) becomes DiagnosticReport.code, OBR-7 becomes effectiveDateTime, and OBR-14 becomes issued. Each OBX segment maps to a separate FHIR Observation resource, with the result set grouped under DiagnosticReport.result references. The OBX value type field (OBX-2) determines the FHIR observation value type: NM (Numeric) maps to valueQuantity with OBX-6 as the unit, CE/CWE maps to valueCodeableConcept, and ST/TX/FT map to valueString.
ORM to ServiceRequest
ORM^O01 messages represent orders. The ORC segment provides order control (ORC-1), placer order number (ORC-2 → ServiceRequest.identifier), filler order number (ORC-3), order status (ORC-5 → ServiceRequest.status), and ordering provider (ORC-12 → ServiceRequest.requester). The OBR segment contributes the procedure code (OBR-4 → ServiceRequest.code), requested date/time (OBR-6 → ServiceRequest.occurrenceDateTime), and priority (OBR-5 → ServiceRequest.priority).
Key Migration Considerations
- Identifier systems: HL7 v2 CX identifiers (PID-3, PV1-19) carry an assigning authority. In FHIR, these should become Identifier.system URIs — ideally OIDs (urn:oid:...) or NamingSystem canonical URLs registered in your FHIR server.
- Terminology: V2 table values (0001 for sex, 0004 for patient class) must be mapped to FHIR-defined code systems. Many organizations need a terminology service or lookup table to handle local codes in OBR-4 or OBX-3.
- Z-segments: Custom Z-segments (ZDG, ZPI, ZRX) have no FHIR equivalent and require extensions or contained resources, adding project complexity.
- Versioning: HL7 v2.3.1, v2.4, v2.5, and v2.5.1 differ in field positions and available data types. A robust mapper must handle multiple versions gracefully.
- Bi-directional flow: Many integration architectures require both v2-to-FHIR and FHIR-to-v2 translation. Design the mapping schema to be reversible where possible.