HL7 v2 vs FHIR vs DICOM: Healthcare Interoperability Architecture Deep Dive
Last Updated: April 19, 2026
Architecture at a glance





Forty years after HL7 v2 first shipped, healthcare IT still runs on pipe-delimited ASCII text wrapped in 7-bit serial framing—yet alongside it flourishes a modern REST-native JSON architecture (FHIR), and imaging departments operate an entirely separate DICOM universe. These three standards coexist because each solves a different problem: HL7 v2 handles the legacy hospital workflow, FHIR enables cloud-native health apps, and DICOM is purpose-built for radiology and medical imaging. Understanding when to use each—and how to integrate them—determines whether your healthcare platform scales or becomes a costly integration nightmare.
TL;DR
HL7 v2 (pipe-delimited message format) dominates legacy hospital IT because it encodes real clinical workflows into segment sequences; FHIR (REST resources, JSON/XML) enables modern EHR interoperability and SMART apps but doesn’t handle imaging; DICOM (image protocol with C-STORE/C-FIND and REST alternatives) owns radiology. Production systems often use all three: HL7 v2 ingress routed through engines like Mirth Connect or Rhapsody, transformed to FHIR resources, stored in cloud platforms (AWS HealthLake, Azure Health Data Services, Google Cloud Healthcare API), with DICOMweb bridging imaging. Why FHIR-only adoption stalls: backward compatibility costs, legacy EMR realities, and the non-trivial DICOM integration. Compliance (USCDI, HIPAA) now mandates FHIR; migration happens in phases, not cutover.
Table of Contents
- Key Concepts Before We Begin
- The Three Standards at a Glance
- HL7 v2: Segment-Based Messages and MLLP Transport
- FHIR: Resource Graphs and REST APIs
- DICOM: Imaging Protocol and DICOMweb
- Modern Integration Architecture
- Benchmarks & Comparison
- Edge Cases & Failure Modes
- Implementation Guide
- Frequently Asked Questions
- Real-World Implications & Future Outlook
- References & Further Reading
Key Concepts Before We Begin
Before diving into the mechanics of each standard, you need to understand the foundational concepts that differentiate them. Healthcare interoperability isn’t about picking the “best” standard—it’s about matching the right tool to the problem. HL7 v2 encodes clinical workflows as ordered sequences of typed records. FHIR models healthcare entities as linked data structures. DICOM treats images as scientific data with embedded metadata. Each reflects a different era and use case.
Segment: In HL7 v2, a segment is a delimited record type (e.g., MSH for message header, PID for patient demographics). Think of it like a table row—each segment has a fixed-position set of fields with defined meaning.
Resource: In FHIR, a resource is a RESTful entity (Patient, Observation, Encounter, Condition) modeled as JSON or XML. Resources link to one another by reference, forming a graph. This is closer to an object-oriented data model.
SOP Class: In DICOM, a Service-Object Pair (SOP Class) defines what type of imaging study you’re transferring (e.g., CT Image Storage, MRI Image Storage, X-Ray). It’s the contract that sender and receiver negotiate before transmitting images.
MLLP (Minimal Lower-Layer Protocol): A thin TCP wrapper around HL7 v2 messages. It adds framing bytes (VT start, FS/CR end) so the receiver knows where one message begins and another ends—essential for a stream-based protocol.
FHIR Conformance/Profile: A FHIR profile constrains a generic resource to match a specific use case (e.g., US Core Patient, which adds must-support fields for EHR vendors). Think of it as a schema on top of FHIR’s base.
DICOMweb: A REST wrapper around DICOM semantics. Instead of negotiating DICOM associations and using C-STORE/C-FIND, you POST/GET over HTTP. Modern imaging vendors increasingly prefer it for cloud deployment.
Integration Engine: Middleware (Mirth Connect, Rhapsody, Lyniate) that listens for HL7 v2 messages, transforms them, routes them, and stores results. It’s the glue that makes legacy and modern systems talk.
The Three Standards at a Glance
Healthcare interoperability has no single standard because the requirements are fundamentally different. The diagram below shows how HL7 v2, FHIR, and DICOM occupy distinct niches in the healthcare data ecosystem.
Setup: What you’re about to see is a side-by-side comparison of the three standards’ architectural primitives. Each row shows how a standard represents the same clinical concept (patient admission, lab observation, imaging study) using its native format and transport.

Walkthrough:
The HL7 v2 column (left) shows how a patient admission (ADT message) is represented as a sequence of segments. The message header (MSH) declares the sending system and message type (ADT^A01 = Admission), followed by PID (patient ID and demographics), then optional clinical segments (OBR for orders, OBX for results). The entire message is framed with MLLP: a vertical tab (VT, 0x0B) before, a file separator + carriage return (FS/CR, 0x1C 0x0D) after. This encoding is ASCII-safe, compressed, and designed for 1980s-era modem speeds. The downside: field delimiters (|, ^, &) are hardcoded positional; parsing requires knowledge of segment structure.
The FHIR column (middle) represents the same admission as linked JSON resources. A Patient resource contains demographic data; an Encounter resource references that Patient and captures the admission event; Observation and Condition resources reference both. Everything is delivered over HTTP/REST: GET /Patient/{id}, POST /Encounter, PATCH /Observation/{id}. There’s no framing, no binary encoding. The structure is self-describing (JSON schema). The downside: more verbose, requires more network round-trips if you want to fetch a patient + all encounters + all observations.
The DICOM column (right) is orthogonal. It’s not about patient data—it’s about images. A CT study contains series (axial, sagittal, coronal), each containing image instances. DICOM encodes the pixel data, image metadata, and patient/study context into a single binary file format. Transfer happens either via C-STORE (a stateful TCP negotiation) or DICOMweb (REST GET/POST). The key difference from FHIR: DICOM is self-contained; one file is the patient’s CT study.
Why not one standard? HL7 v2 won because it shipped in the 1990s and hospitals rewrote their entire EMR around it—switching costs are enormous. FHIR was designed for a REST-native world and mandated by regulation (21st Century Cures Act). DICOM exists because radiology has very different data (images, pixel-level metadata) and very different performance requirements (gigabytes per study) than other clinical domains. They’re not in competition; they’re in parallel.
HL7 v2: Segment-Based Messages and MLLP Transport
HL7 v2 remains the backbone of hospital IT despite its age and quirks. To understand why it endures, you need to see how it encodes clinical workflows as ordered message types, and how integration engines route those messages at scale.
HL7 v2 is a message standard, not a data model. It describes how to encode discrete clinical events (patient admission, lab result, medication order) as ASCII text. A hospital’s LIS (lab information system) emits an ORU^R01 (observation result unsolicited) when a lab panel completes. The EMR listens for ORU messages and imports results into the patient’s chart. The order entry system sends ORM (order messages) to the lab. This pub-sub pattern, encoded as text, became the lingua franca of healthcare IT.
Architecture and Message Structure:
The most basic unit is the message, which is a sequence of segments. Each segment is a line of pipe-delimited fields. The diagram below decomposes a realistic ADT^A01 (patient admission) message into its constituent parts and explains the delimiters and field meanings.
Setup: What you’re about to see is a zoomed-in view of how HL7 v2 encodes a patient admission. The top shows the MLLP framing bytes; the middle shows a real message; the bottom shows the segment breakdown. This is what integration engineers parse every day.

Walkthrough:
Every HL7 v2 message starts with an MSH (message header) segment. The first three characters are literally MSH, followed by the field delimiter (usually |). The MSH segment also declares the other delimiters: component separator (^), repetition separator (~), escape character (\), and subcomponent separator (&). This allows a message to define its own grammar—a clever but fragile design.
The PID segment encodes patient demographics. Field PID-3 is the patient’s medical record number (usually a composite ID with check digit). PID-5 is the patient’s name (a composite: family^given^middle). PID-7 is date of birth. Real hospital systems have hundreds of PID fields defined, many vendor-specific.
The OBR segment represents an order—say, a complete metabolic panel. OBR-1 is the set ID (sequence number). OBR-4 is the order code (e.g., LOINC 24365-2 for Comprehensive Metabolic Panel). OBR-6 is the requested time.
The OBX segment is the observation result—one lab value. If the panel has 14 results (glucose, electrolytes, etc.), there are 14 OBX segments in sequence. OBX-2 is the value type (NM for numeric, TX for text). OBX-5 is the actual value. OBX-6 is the unit (mg/dL).
The MLLP wrapper adds a VT byte (0x0B, vertical tab) before the message and FS + CR bytes (0x1C + 0x0D) after. This allows the receiver to detect message boundaries in a TCP stream, crucial for reliability when messages arrive back-to-back.
Parsing Mechanics:
Parsing HL7 v2 is deceptively complex. The delimiters are context-free; a pipe inside a patient name (e.g., “Smith|Jones”) breaks parsing. That’s why the escape character exists: \S\ escapes a component separator. But escape sequences are nested—\\ is a literal backslash. And different vendors interpret escaping differently, leading to integration nightmares.
A typical parser splits on | to get segments, then splits each segment on ^ to get components, then on & for subcomponents. But a robust parser must:
– Detect the delimiters from MSH
– Handle escape sequences
– Validate segment sequences (e.g., PID must come before OBX)
– Handle vendor-specific extensions
Transport and Reliability:
HL7 v2 messages are sent over MLLP, which is a stateless, message-oriented protocol layered on TCP. The sender opens a connection, sends one or more messages, and waits for acknowledgments. The receiver sends back an ACK or NAK (negative acknowledgment) for each message. If the sender doesn’t receive an ACK within a timeout, it retransmits.
This is not a reliable protocol by modern standards. If the network fails mid-message, the receiver may have a partial message. If the sender crashes after sending but before receiving the ACK, the message may be lost. That’s why integration engines often log every message to a database and implement their own deduplication logic.
Why HL7 v2 Endures:
HL7 v2’s longevity is not due to technical elegance. It’s due to:
- Workflow embedding: The segment sequence mirrors the clinical workflow. Ordering → results → billing → discharge. This made it intuitive for hospital IT managers in the 1990s.
- Backward compatibility: Every EMR vendor shipped HL7 v2 interfaces. Switching costs are astronomical. A large health system might have 200+ HL7 v2 integrations (lab, pharmacy, radiology, billing, insurance).
- Compactness: A compressed HL7 v2 message is tiny—often under 1KB. For 1990s modem links, this mattered.
- No central registry: Unlike FHIR, HL7 v2 doesn’t require a centralized FHIR server. You just route messages point-to-point. This made it easier to deploy in the pre-cloud era.
FHIR: Resource Graphs and REST APIs
FHIR (Fast Healthcare Interoperability Resources, pronounced “fire”) was standardized by HL7 in 2014 and mandated by U.S. regulation (21st Century Cures Act in 2015) as the future of healthcare data exchange. Unlike HL7 v2’s message-oriented paradigm, FHIR treats healthcare entities as REST resources that can be queried, linked, and composed.
Resource-Oriented Design:
In FHIR, the primary abstraction is the resource—a JSON or XML document representing a discrete clinical entity. There are 140+ FHIR resources defined by the standard. The core clinical resources are:
- Patient: Demographics, identifiers, contact info, language.
- Encounter: A visit (e-in, checkout, admission). References a Patient.
- Observation: A lab value, vital sign, or clinical measurement. References a Patient and optionally an Encounter.
- Condition: A diagnosis. References a Patient.
- CarePlan: A treatment plan. References Patient, Encounter, and Conditions.
- Medication: A drug. Referenced by MedicationRequest.
- MedicationRequest: An order for a drug. References Patient and Medication.
Each resource has a canonical REST endpoint. To fetch a patient:
GET /Patient/12345
Returns:
{
"resourceType": "Patient",
"id": "12345",
"identifier": [
{
"system": "http://hospital.example.com/MRN",
"value": "987654321"
}
],
"name": [
{
"family": "Smith",
"given": ["John"]
}
],
"gender": "male",
"birthDate": "1980-05-15"
}
To create an observation:
POST /Observation
Content-Type: application/fhir+json
{
"resourceType": "Observation",
"status": "final",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "2345-7",
"display": "Glucose [Mass/volume] in Serum or Plasma"
}
]
},
"subject": {
"reference": "Patient/12345"
},
"effectiveDateTime": "2026-04-19T14:30:00Z",
"value": {
"value": 95,
"unit": "mg/dL",
"system": "http://unitsofmeasure.org",
"code": "mg/dL"
}
}
Resource Graphs and Linkage:
The diagram below shows how FHIR resources form a directed graph. A Patient is the root; Encounters reference the Patient; Observations reference both Patient and Encounter; Conditions reference the Patient. This creates a queryable graph.
Setup: What you’re about to see is how FHIR resources link to one another. Each resource is a node; arrows are references. This is different from HL7 v2’s linear segment sequence—it’s a true data graph.

Walkthrough:
The Patient resource is the central hub. It contains the patient’s identity, demographics, and contact information. It does not contain clinical data; it’s purely identifying.
Encounter resources reference a Patient via the subject field. An Encounter represents a single visit or admission. It has a status (planned, arrived, in-progress, onleave, finished, cancelled), a type (outpatient, inpatient, emergency, etc.), and a period (start and end time).
Observation resources reference both Patient (who had the observation) and Encounter (in which context). Observations are leaf nodes—a single lab value, vital sign, or imaging finding. An Observation has a code (from LOINC or SNOMED CT), a value, a status (registered, preliminary, final, amended, cancelled, entered-in-error, unknown), and an effective date/time.
Condition resources represent diagnoses. They reference a Patient and optionally an Encounter. A Condition has a code (from ICD-10 or SNOMED CT), a stage, severity, and a recorded date.
CarePlan resources link Patient, Encounter, and Conditions. They represent the care team’s plan for the patient.
Bundle resources are containers for multiple resources. A Bundle can be transaction (atomic submit), batch (submit multiple), search-set (search results), or message (HL7 FHIR message—a new paradigm). Bundles enable sending multiple related resources in one HTTP request.
Search and Filtering:
FHIR defines a search syntax. To find all observations for a patient with code 2345-7 (glucose):
GET /Observation?subject=Patient/12345&code=2345-7
Returns a Bundle of matching Observations. Search parameters are standardized across resources. Filtering on date, status, text, etc. is built in.
Subscriptions and Real-Time Updates:
FHIR Subscriptions allow a client to register interest in events. For example, “notify me when any Observation for Patient/12345 is created or updated.” The server invokes a webhook on the client. This is REST-native event streaming, replacing HL7 v2’s point-to-point message routing.
SMART on FHIR:
SMART (Substitutable Medical Applications and Reusable Technology) is a framework for building health apps that run inside EHRs. A SMART app is a web app (React, Vue, etc.) that authenticates via OAuth 2.0 and uses FHIR REST APIs to fetch patient data. For example, a glucose management app might:
- Authenticate via OAuth (user approves the app in the EHR)
- GET /Patient/{id} (fetch patient demographics)
- GET /Observation?subject=Patient/{id}&code=2345-7 (fetch glucose readings)
- POST /CarePlan (create a care plan for glucose management)
This enables third-party developers to build EHR apps without accessing the EHR’s internal database—a huge unlock for the app ecosystem.
Bulk Data API:
For analytics and compliance, FHIR defines Bulk Data API (de facto standard, moving toward formal spec). Instead of paginating individual resources, a client can request a bulk export:
POST /$export?_type=Observation,Condition
The server returns NDJSON (newline-delimited JSON) files, one resource per line, in S3 or equivalent. This is designed for data warehouse loading.
Why FHIR-Only Adoption Stalls:
Despite its elegance, pure FHIR adoption is slow. Why?
- Backward compatibility: Every existing HL7 v2 integration must be rewritten. That’s hundreds of transformations for a large health system. Hospitals do this incrementally, not all at once.
- Imaging doesn’t fit: FHIR has an ImagingStudy resource, but it’s a metadata wrapper around DICOM. You still need a DICOMweb server for actual image data. So you’re managing two protocols anyway.
- Real-time semantics: FHIR’s REST model is request-response, not stream-based like HL7 v2. Real-time lab results (which need to flow to clinician screens immediately) require Subscriptions, which not all EHRs support well yet.
- EMR architecture: Most legacy EMRs have HL7 v2 baked into their core. Ripping it out and replacing it with FHIR is a multi-year rewrite.
DICOM: Imaging Protocol and DICOMweb
DICOM (Digital Imaging and Communications in Medicine) is the standard for radiology and medical imaging. It’s orthogonal to HL7 v2 and FHIR; it solves a completely different problem: how to transmit gigabytes of imaging data with precise metadata about acquisition parameters, patient context, and image processing.
The DICOM Ecosystem:
DICOM defines:
- File format: A binary container for image pixels, metadata (patient, study, series, image level), and processing history.
- Network protocol: DIMSE (DICOM Message Service Element), a stateful protocol for querying (C-FIND), storing (C-STORE), and retrieving (C-GET) images.
- REST wrapper: DICOMweb, a modern REST alternative to the legacy network protocol.
A typical radiology workflow:
- Technician schedules a CT study via the RIS (Radiology Information System), which sends an order.
- CT scanner acquires images and sends them to a PACS (Picture Archiving and Communication System) via DICOM C-STORE. The C-STORE negotiation includes agreement on SOP Classes (e.g., CT Image Storage, Secondary Capture).
- Radiologist queries PACS via C-FIND to find studies for a patient.
- Radiologist retrieves selected images via C-GET or WADO-RS (if DICOMweb is enabled).
- Radiologist reports findings; report is saved and linked to the study.
DICOM Network Architecture:
The diagram below shows how DICOM associations work and how DICOMweb provides a REST alternative.
Setup: What you’re about to see is the DICOM network model. The left side shows the legacy C-STORE/C-FIND association-based protocol. The right side shows the modern REST-based DICOMweb alternative. Both can coexist in a modern PACS.

Walkthrough:
In C-STORE (legacy), the process works as follows: A DICOM client (sender, identified by an AE title and listening on a port, e.g., MYSCANNER:11112) initiates a TCP connection to the DICOM server (e.g., PACS_SERVER:104). They negotiate an A-ASSOCIATE request, in which the client and server agree on which SOP Classes they’ll support. For example, the client might declare “I can send CT Image Storage,” and the server responds “I accept CT Image Storage and Secondary Capture.” Once associated, the client sends C-STORE-RQ (request) messages containing image data. The server responds with C-STORE-RSP (success or failure). After all images are sent, the client sends A-RELEASE to close the association. This is a stateful, negotiated protocol. It’s reliable (TCP) but verbose and slow for high-volume imaging.
In C-FIND, a querier (client) associates with a provider (server) and sends a C-FIND-RQ with query keys—e.g., “find all studies for patient Smith on 2026-04-15.” The provider responds with matching studies. The query language is DICOM-specific; you can’t use SQL or JSON Query Language.
DICOMweb (modern, REST-based) replaces the association model:
- QIDO-RS (Query Information and Dicom Objects): GET
/dicomweb/studies?PatientName=Smith. Returns JSON metadata (study UID, series UIDs, modality, etc.) without image pixels. - WADO-RS (Web Access to DICOM Objects): GET
/dicomweb/studies/{studyUID}/series/{seriesUID}/instances/{instanceUID}. Returns the actual DICOM file or multipart response with metadata and frames. - STOW-RS (Store Web Objects): POST
/dicomweb/studieswith multipart DICOM data. Stores images without association negotiation.
DICOMweb is HTTP/REST, so it works through firewalls, load balancers, and proxies. No connection state. It’s naturally cloud-friendly.
SOP Classes and Modality:
A SOP Class (Service-Object Pair) uniquely identifies a type of imaging (CT, MRI, X-Ray, Ultrasound, etc.). Each SOP Class has a UID (e.g., 1.2.840.10008.5.1.4.1.2 for CT Image Storage). DICOM mandates that sender and receiver agree on SOP Classes before C-STORE. This prevents surprises—you don’t accidentally send a 3D ultrasound volume to a server that only handles 2D X-Ray images.
DICOM Metadata:
Every DICOM file contains metadata at three levels:
- Patient level: Patient ID, name, date of birth.
- Study level: Study UID, study description, study date, referring physician.
- Series level: Series UID, series number, series description, modality (CT, MR, XC for secondary capture).
- Image level: Instance UID, acquisition parameters (slice thickness, field of view, pixel spacing), image position/orientation, rescale slope/intercept for intensity values.
This metadata allows a radiologist to understand the image without opening it in viewing software. And it enables automated processing—a workflow can filter images by modality, slice thickness, or acquisition date.
DICOM and FHIR Integration:
FHIR has an ImagingStudy resource that wraps DICOM metadata. An ImagingStudy resource looks like:
{
"resourceType": "ImagingStudy",
"id": "12345",
"subject": {
"reference": "Patient/67890"
},
"started": "2026-04-19T10:30:00Z",
"procedureCode": [
{
"coding": [
{
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "CT"
}
]
}
],
"basedOn": [
{
"reference": "ServiceRequest/54321"
}
],
"series": [
{
"uid": "1.2.3.4.5.6.7.8.9",
"modality": {
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "CT"
},
"instance": [
{
"uid": "1.2.3.4.5.6.7.8.9.1",
"title": "Axial CT Thorax"
}
]
}
]
}
The ImagingStudy references the Patient and contains series and instance UIDs. However, it does not contain image pixels—those are retrieved via DICOMweb. So in a modern stack, you have FHIR for metadata and DICOMweb for image data.
Modern Integration Architecture
No healthcare organization uses one standard in isolation. A real system typically ingests HL7 v2 from legacy systems, transforms to FHIR, stores in a cloud platform, integrates imaging via DICOMweb, and serves SMART apps on top. This requires integration engines, cloud health platforms, and careful data mapping.
Diagram and Workflow:
The diagram below shows a realistic architecture where legacy HL7 v2 systems feed into a transformation engine, which outputs FHIR resources stored in a cloud health platform. Imaging systems feed DICOMweb servers. Consumer apps query both.
Setup: What you’re about to see is a production-style integration: HL7 v2 legacy sources → transformation → FHIR store. Imaging systems operate in parallel via DICOMweb. Analytics and compliance are downstream.

Walkthrough:
A legacy LIS or HIS emits HL7 v2.5 messages (ORU, ADT, ORM). An MLLP listener (often running in Mirth Connect, Rhapsody, or Lyniate) accepts these messages and parses them. A transform engine converts HL7 v2 into FHIR resources. For example:
- HL7 v2 PID segment → FHIR Patient resource
- HL7 v2 OBR + OBX segments → FHIR Observation resource
- HL7 v2 ADT^A01 → FHIR Encounter resource
The transform is not 1:1. HL7 v2 has ~300 segments defined across all versions; FHIR has ~140 resources. Mapping is often lossy. For example, HL7 v2 PID-8 (administrative sex) maps cleanly to FHIR Patient.gender, but HL7 v2’s vendor-specific extensions may not have FHIR equivalents.
The transformed FHIR resources are written to a FHIR store. Cloud platforms offer managed FHIR services:
- AWS HealthLake: FHIR-compliant data store with search, Subscriptions, and Bulk Data API. Integrates with AWS Lambda for transforms.
- Azure Health Data Services: FHIR Server, DICOM Server, and MedTech service for HL7 v2 ingestion.
- Google Cloud Healthcare API: FHIR store, DICOM store, and HL7 v2 ingestion service.
Imaging systems (CT, MRI, X-Ray) send DICOM images via C-STORE to a DICOMweb server (standalone PACS or cloud-based like AWS HealthLake’s DICOM Store). The DICOMweb server exposes REST endpoints for querying (QIDO-RS) and retrieving (WADO-RS).
A consumer app (SMART on FHIR or custom) queries the FHIR store via REST (GET /Patient, GET /Observation) and the DICOMweb server via REST (GET /studies). It may also consume a Bulk Data API export for analytics—the FHIR store produces NDJSON exports that land in a data warehouse.
Transformation Patterns:
Mapping HL7 v2 to FHIR is non-trivial. Common challenges:
- Repeating groups: HL7 v2 OBX segments repeat for multiple results; FHIR creates separate Observation resources. You must track sequence numbers to group related results.
- Code systems: HL7 v2 often uses local codes (e.g., “GLU” for glucose); FHIR mandates standard code systems (LOINC, SNOMED CT). Mapping requires a lookup table.
- Composite fields: HL7 v2 PID-5 (name) is a single field with subcomponents; FHIR Patient.name is an array of name objects. A patient with multiple name variants requires multiple array elements.
- Timestamps: HL7 v2 timestamps are HL7-formatted (YYYYMMDDHHmmss); FHIR expects ISO 8601 (2026-04-19T14:30:00Z). Conversion and timezone handling are error-prone.
- Missing data: HL7 v2 may omit optional fields; FHIR profiles mandate certain fields (“must-support”). If source data is missing, you must decide: use a default, null, or fail the transform?
Integration engines (Mirth, Rhapsody) provide DSL and UI for building transformations. But they require expertise and testing. A common pattern:
- Define HL7 v2 parsing rules (segment sequence, field counts).
- Define FHIR resource schema (required fields, code systems).
- Map fields with a rule engine.
- Validate FHIR output against profiles.
- Log failures and create exception handling.
Compliance and USCDI:
The U.S. Core Data for Interoperability (USCDI) mandates that EHRs expose certain data via FHIR APIs. As of 2024, USCDI includes:
- Patient demographics
- Laboratory results
- Vital signs
- Medications and medication requests
- Problem lists (diagnoses)
- Procedures
- Immunizations
- Care plans
- Goals
- Encounter information
EHRs must expose this data via FHIR APIs compliant with US Core profiles (e.g., US Core Patient, US Core Observation Lab Result). This drives the adoption of FHIR in EHRs and integration engines. However, it doesn’t mandate HL7 v2 removal—many EHRs still rely on HL7 v2 internally.
Benchmarks & Comparison
The table below compares the three standards across key dimensions. This is designed to help you choose when to use each.
| Dimension | HL7 v2 | FHIR | DICOM |
|---|---|---|---|
| Primary Use Case | Hospital workflow messages (ADT, ORU, ORM) | RESTful health data access and interoperability | Medical imaging data and metadata |
| Data Model | Segment-based, ordered sequences | Resource graph, linkable entities | Binary image container + metadata |
| Transport | MLLP (TCP, stateful) | HTTP/REST, stateless | C-STORE (association), DICOMweb (REST) |
| Encoding | ASCII text, pipe-delimited | JSON or XML | Binary (DICOM file format) |
| Typical Message Size | 0.5–5 KB | 1–50 KB | 100 KB–1 GB (per image) |
| Query Language | None (segment-based routing) | FHIR search parameters (SQL-like filters) | C-FIND (DICOM tags) or QIDO-RS (JSON) |
| Real-Time Streaming | Yes (publish-subscribe via point-to-point messages) | Via Subscriptions (webhooks), not native | Via C-MOVE/WADO subscription (limited) |
| Backward Compatibility | Excellent (v2.3, v2.4, v2.5 coexist) | Versioned (R4 current, R5 draft) | Excellent (multiversion DICOM libraries) |
| Adoption in U.S. | ~95% of hospitals | ~40% of EHRs (mandated by regulation, growing) | ~100% of radiology departments |
| Cloud-Native | Poor (MLLP assumes persistent TCP) | Excellent (REST, stateless, scalable) | Moderate (DICOMweb is REST; C-STORE is legacy) |
| Standardization | HL7 International | HL7 International (FHIR.org) | NEMA (National Electrical Manufacturers Association) |
Key Observations:
-
HL7 v2 message size is tiny. A full patient admission encoded in HL7 v2 is often < 1 KB. FHIR equivalent is 10–20 KB. For mobile networks or IoT integration, this matters.
-
FHIR is designed for modern APIs. Stateless, HTTP, no connection management. If you’re building a cloud app, FHIR is easier than HL7 v2 + MLLP.
-
DICOM is imaging-specific. You don’t use DICOM for lab results or medications. But if you’re integrating imaging, you can’t avoid it.
-
Query capabilities differ. HL7 v2 is message-driven (push); FHIR is request-driven (pull). DICOM is query-driven (pull via C-FIND or QIDO-RS). For real-time alerts (“new critical lab value”), HL7 v2 is faster. For historical queries (“all glucose readings”), FHIR is more natural.
-
Adoption is driven by regulation, not technical merit. HL7 v2 survives because it’s embedded. FHIR adoption accelerates because the 21st Century Cures Act mandates it. This is a reminder that healthcare IT is path-dependent.
Edge Cases & Failure Modes
Real-world healthcare integration is messy. Standards are complex, vendors implement them differently, and clinical workflows don’t always fit the model. Here are common failure modes and mitigations.
HL7 v2 Parsing Failures:
Problem: A vendor sends HL7 v2 with non-standard escape sequences or missing fields. Your parser throws an error and drops the message.
Example: A lab system sends “Smith\T\Jones” intending to represent the patient name as “Smith|Jones” (two names), but your parser interprets \T\ as an escape for the pipe character (which doesn’t exist in HL7 v2’s official escape sequences). The message is malformed.
Mitigation: Build lenient parsers that skip or default unknown escapes. Log all parsing errors to a database. Implement manual review and correction workflows. Use mature integration engines (Mirth, Rhapsody) that have years of vendor-specific quirk handling baked in.
FHIR Profile Violations:
Problem: You create a FHIR Observation with a code from a non-standard code system (e.g., local lab code instead of LOINC). A downstream system expecting LOINC codes fails to process it.
Example: Your lab system uses local code “GLU” for glucose. You map it to FHIR Observation.code.coding[0].code = “GLU” with system = “http://example.com/lab-codes”. A third-party app expecting LOINC (system = “http://loinc.org”) ignores the observation.
Mitigation: Define FHIR profiles early. Require bidirectional code mapping (local ↔ LOINC/SNOMED CT). Validate resources against profiles before storage. Use a terminology service (e.g., VSAC, SNOMED CT browsers) to verify code validity.
DICOM SOP Class Mismatch:
Problem: A scanner sends CT Image Storage (SOP Class 1.2.840.10008.5.1.4.1.2), but the PACS only supports Secondary Capture (1.2.840.10008.5.1.1.7). The C-STORE association fails.
Example: A mobile ultrasound cart sends 3D ultrasound volumes (SOP Class for Ultrasound Multi-frame Image Storage), but an older PACS expects 2D frames. Images are rejected.
Mitigation: Inventory all SOP Classes supported by each DICOM device (scanners, PACS, viewers). Use a DICOM conformance statement from the vendor. Implement format conversion gateways (e.g., convert secondary capture to CT if needed). Use DICOMweb as a universal interface; REST servers can negotiate SOP Classes via HTTP headers.
Data Loss in Transformation:
Problem: You transform HL7 v2 OBX segments to FHIR Observation resources. A field in OBX (e.g., OBX-15, the producer’s ID) doesn’t map to any FHIR Observation field. The information is lost.
Example: Your lab sends OBX-15 (instrument ID that ran the test). FHIR Observation has no native field for instrument ID. You drop the information. Later, the lab needs to recall results from a malfunctioning instrument—but you have no way to identify them.
Mitigation: Map all non-essential fields to FHIR extension objects. FHIR allows vendor-specific extensions: Observation.extension[0].url = "http://example.com/instrument-id", Observation.extension[0].valueString = "HEMATOLOGY-01". This preserves the information without breaking FHIR compliance.
Duplicate Detection:
Problem: An HL7 v2 message is sent twice (network retry, application crash and recovery). Your integration engine processes it twice, creating duplicate Observations.
Example: Lab sends ORU message with ID ABC123. Your integration engine receives it, processes it, and sends an ACK. But the ACK is lost due to network lag. The lab retransmits. You process the message again, creating two Observation resources.
Mitigation: Deduplicate on message ID (MSH-10 in HL7 v2, Bundle.id in FHIR). Store a map of processed IDs in a database. Before processing, check if the message ID has been seen before. If so, check if the output already exists. If yes, return idempotent success (don’t reprocess). If no, process and store.
Timestamp and Timezone Issues:
Problem: An HL7 v2 message includes a timestamp without timezone info. You convert it to ISO 8601, assuming UTC. Later, you discover it was meant to be in the patient’s local timezone. Subsequent queries or analytics use the wrong timestamp.
Example: Lab sends OBX-14 (date of observation) as “20260419143000” (no timezone). You store it as “2026-04-19T14:30:00Z” (UTC). But the lab is in Pacific time, so the true time is 2026-04-19T21:30:00Z (UTC). Queries for “observations in the past 24 hours” may miss this observation.
Mitigation: Always require timezone in source data. If missing, document the assumption (e.g., “all timestamps assumed UTC unless specified”). Use ISO 8601 with explicit timezone in FHIR. Implement a timezone service that maps facility IDs to timezones. Test with cross-timezone edge cases.
Implementation Guide
If you’re building a healthcare interoperability system from scratch or migrating to FHIR, here’s a phased approach.
Phase 1: Assessment (Weeks 1–4)
-
Inventory existing integrations. List all HL7 v2, FHIR, and DICOM interfaces. For each, document:
– Data flow (source → target)
– Message types (ADT, ORU, ORM, etc.)
– Frequency and volume
– Criticality (if it breaks, what breaks downstream?) -
Map current data model. Create a data dictionary:
– Patient identifiers (MRN, social security number, etc.)
– Clinical concepts (lab codes, diagnosis codes, medication codes)
– Code systems in use (local codes, LOINC, SNOMED CT, ICD-10) -
Define target state. Decide:
– Will you migrate to FHIR? (Likely yes if under USCDI pressure)
– Will you keep HL7 v2 ingestion? (Likely yes if legacy systems are stable)
– What’s your imaging strategy? (DICOM C-STORE, DICOMweb, or both?)
Phase 2: Foundation (Weeks 5–16)
-
Select a FHIR platform. Choose between:
– Managed cloud (AWS HealthLake, Azure Health Data Services, Google Cloud Healthcare API): Higher cost, less operational overhead.
– Open-source (HAPI FHIR, Smile CDR): Lower cost, requires operations expertise. -
Select an integration engine. If you have HL7 v2 ingestion:
– Commercial: Mirth Connect, Rhapsody (Interpolua), Lyniate (formerly Capsule), Boomi
– Open-source: Camel, NiFi, custom Lambda functions -
Build HL7 v2 → FHIR transforms. Start with high-volume message types (ADT, ORU). Use your data dictionary to map fields. Validate against FHIR profiles (US Core if applicable).
-
Set up monitoring and error handling. Create dashboards for:
– Message receive rate, transform rate, store rate
– Error rate and top error types
– Latency (time from receive to store)
Phase 3: Pilot (Weeks 17–24)
-
Run a pilot integration. Pick one clinical department (lab, pharmacy, or radiology) and pilot the full pipeline:
– Legacy system → integration engine → FHIR store
– Test data, not production data
– Run for 2–4 weeks; collect failures and iterate -
Validate data integrity. Spot-check transformed data:
– Pick 10 random HL7 v2 messages; manually verify the FHIR output
– Ensure no data loss (use FHIR extensions for unmapped fields)
– Test edge cases (missing fields, non-standard codes) -
Load test. Simulate peak volume (e.g., 1000 messages/second if your lab peaks there). Measure:
- Transform latency (p95, p99)
- FHIR store throughput
- Integration engine CPU, memory, disk
Phase 4: Rollout (Weeks 25+)
-
Migrate additional departments. Roll out to more clinical areas incrementally.
-
Stand up consumer applications. Build or enable SMART on FHIR apps:
- Patient portal
- Clinician dashboard
- Analytics queries
-
Communicate with stakeholders. Make sure vendors, clinicians, and IT operations are aware of the migration. FHIR adoption is a social and technical change.
Code Example: HL7 v2 to FHIR Transform (Pseudocode)
function transform_hl7_to_fhir(hl7_message) {
segments = parse_hl7_segments(hl7_message)
msh = segments['MSH'][0]
pid = segments['PID'][0]
obr_obx = group_obr_obx(segments['OBR'], segments['OBX'])
// Create Patient resource
patient = {
resourceType: "Patient",
identifier: [{
system: "http://hospital.example.com/MRN",
value: pid.field(3) // PID-3: Medical Record Number
}],
name: [{
family: pid.field(5).component(0), // PID-5: Family Name
given: [pid.field(5).component(1)] // PID-5: Given Name
}],
gender: map_gender(pid.field(8)), // PID-8: Gender
birthDate: pid.field(7).substring(0, 8) // PID-7: Date of Birth (YYYYMMDD)
}
// Create Encounter resource
encounter = {
resourceType: "Encounter",
status: "finished",
subject: { reference: "Patient/" + patient.id },
type: [{
coding: [{
system: "http://example.com/encounter-type",
code: msh.field(9).component(0) // MSH-9: Message Type, first component
}]
}]
}
// Create Observation resources for each OBX segment
observations = []
for obx in obr_obx.observations {
obs = {
resourceType: "Observation",
status: "final",
code: {
coding: [{
system: "http://loinc.org",
code: lookup_loinc(obx.field(3)) // OBX-3: Observation ID → LOINC
}]
},
subject: { reference: "Patient/" + patient.id },
encounter: { reference: "Encounter/" + encounter.id },
effectiveDateTime: obx.field(14), // OBX-14: Date/Time of Observation
value: {
value: parse_numeric(obx.field(5)) // OBX-5: Observation Value
}
}
observations.append(obs)
}
// Validate and store
validate_fhir_bundle([patient, encounter] + observations)
store_to_fhir_server([patient, encounter] + observations)
}
Operational Best Practices:
-
Version your transforms. If you change a mapping rule (e.g., how you convert ICD-9 to ICD-10), version it and track which messages used which version.
-
Log everything. Log the raw HL7 v2 message, the parsed segments, the transformed FHIR resources, and any errors. This is essential for debugging and compliance audits.
-
Set up alerting. Alert on:
– Transform error rate > 1%
– Message queue depth growing indefinitely (sign of downstream backlog)
– FHIR store latency > 5 seconds (sign of resource exhaustion) -
Implement circuit breakers. If the FHIR store is down, queue messages locally instead of failing immediately. Retry with exponential backoff.
-
Test disaster recovery. Simulate data loss, message loss, and network partitions. Ensure you can recover without data corruption.
Frequently Asked Questions
Q: Can I completely replace HL7 v2 with FHIR?
A: Not overnight. FHIR is the future, but legacy EMRs are deeply integrated with HL7 v2. Large health systems typically run both in parallel for 5–10 years. Regulatory pressure (USCDI, 21st Century Cures) accelerates FHIR adoption, but operational inertia keeps HL7 v2 alive. Practical approach: new integrations use FHIR; legacy HL7 v2 integrations continue until system replacement.
Q: What’s the performance difference between HL7 v2 and FHIR?
A: HL7 v2 messages are smaller (0.5–5 KB) and don’t require JSON parsing; FHIR messages are larger (1–50 KB) and require more processing. However, FHIR’s HTTP/REST architecture is more scalable than HL7 v2’s persistent TCP connections. For real-time streaming (e.g., 10,000 messages/second), HL7 v2 + MLLP may be faster. For request-response workflows (e.g., “fetch all observations for patient”), FHIR is more natural and faster due to HTTP caching and CDN support.
Q: How do I handle code system mapping (local codes → LOINC)?
A: Maintain a code translation table (usually in a database). For each local code, store the LOINC equivalent. When transforming HL7 v2 to FHIR, query the table. If no mapping exists, either fail gracefully (log error, don’t transform), or use a temporary “unknown” LOINC code and flag for manual review. For governance, have clinical informaticists maintain the mapping table; don’t let engineers guess.
Q: Is DICOM going away? Should I invest in DICOMweb?
A: DICOM is not going away—radiology is deeply invested in it. But DICOMweb is becoming the standard interface for cloud and mobile access. Recommendation: new DICOM systems should support both C-STORE (for existing devices) and DICOMweb (for modern clients). Existing PACS should add DICOMweb support via a gateway or upgrade.
Q: What if a vendor only supports HL7 v2, not FHIR?
A: You still have options: (1) Run an integration engine that accepts HL7 v2 and transforms to FHIR; (2) Wait for the vendor’s FHIR roadmap (many have announced plans); (3) Use a third-party adapter or middleware. The reality is that not all vendors are on the same timeline. Plan for coexistence.
Q: How do I ensure HIPAA compliance in transformation?
A: Transformations must preserve all PHI (protected health information) and not add risks. Best practices: (1) Encrypt all data in transit (TLS 1.3); (2) Encrypt at rest in FHIR store and integration engine databases; (3) Implement audit logging (who accessed what data, when); (4) Use role-based access control; (5) Anonymize test data (remove real PHI during development); (6) Conduct security reviews; (7) Maintain Business Associate Agreements with cloud vendors.
Q: Can I use FHIR for EHR-to-EHR exchange instead of HL7 v2?
A: Yes, increasingly. The direct-to-clinician workflow (e.g., referral notes, hospital discharge summaries) can use FHIR Documents (a Bundle of resources wrapped in a Composition resource). Vendors are building this now. However, transactional workflows (orders, results, ADT) still often use HL7 v2 or evolving HL7 FHIR Messaging.
Real-World Implications & Future Outlook
Healthcare interoperability is at an inflection point. Regulation (USCDI, 21st Century Cures) has mandated FHIR adoption, breaking the vendor lock-in that kept HL7 v2 dominant for 30 years. But the transition is not instantaneous.
Current State (2026):
- HL7 v2 dominance: ~95% of U.S. hospitals still rely on HL7 v2 for core integrations. It’s not going away.
- FHIR ramp: ~40% of EHRs now expose FHIR APIs. Mandated by regulation, growing faster than FHIR’s technical merits alone would suggest.
- Hybrid architectures: Most large health systems are running HL7 v2 + FHIR in parallel. Integration engines are adding FHIR support.
- DICOM stability: DICOM is stable; DICOMweb is the forward path, but C-STORE will coexist for decades.
Emerging Trends:
-
Cloud health platforms are the default. AWS HealthLake, Azure Health Data Services, and Google Cloud Healthcare API are becoming the infrastructure of choice for new health systems and initiatives. They handle HL7 v2 ingestion, FHIR storage, and DICOM storage in one stack.
-
SMART on FHIR apps are proliferating. EHRs are adding SMART app stores. Third-party developers can now build patient portals, clinician dashboards, and data analytics tools without touching the EMR’s internal database. This is a fundamental shift in healthcare IT architecture.
-
Real-time FHIR is nascent. FHIR Subscriptions are not yet widely implemented, but they’re coming. Real-time streaming of lab results, patient alerts, and care plan updates via FHIR is the next frontier.
-
Standards profiling is critical. FHIR is extensible and flexible, which is a feature and a bug. Different vendors implement FHIR differently. US Core profiles, USCDI definitions, and CARIN Blue Button specifications are normalizing this, but fragmentation remains a risk. Profiling is the battleground of 2026–2030.
-
Data interoperability ≠ semantic interoperability. You can exchange FHIR documents and DICOM images, but understanding what they mean requires terminologies (LOINC, SNOMED CT, ICD-10). Semantic interoperability—ensuring that “hemoglobin” means the same thing in two systems—is harder than syntactic interoperability. This is why code system mapping is a constant pain point.
Future Outlook (2028+):
- HL7 v2 becomes legacy. New greenfield integrations will be FHIR-first. HL7 v2 will be relegated to connectors and gateways for systems that haven’t migrated.
- FHIR as the lingua franca. FHIR will be the default for EHR-to-EHR exchange, patient portals, and analytics. Regulatory mandates will have been internalized by vendors.
- DICOMweb as the standard imaging interface. C-STORE will still exist, but DICOMweb will be primary for new deployments and cloud-based PACS.
- Semantic interoperability becomes a business problem. Once syntactic interoperability is solved (FHIR, DICOMweb), the next frontier is ensuring that exchanged data is semantically correct. This requires governance, not standards.
References & Further Reading
Primary Standards Documents:
- HL7 International. (2015). HL7 Version 2.5.1 Standard. http://www.hl7.org/implement/standards/product_brief.cfm?product_id=185
- HL7 International. (2019). FHIR R4 (Release 4). https://www.hl7.org/fhir/R4/
- NEMA. (2024). DICOM Standard 2024. https://www.dicomstandard.org/
- DICOMweb Standard (IHE ITI-91). http://www.ihe.net/uploadedFiles/Documents/ITI/IHE_ITI_TF_Volume2b.pdf
RFCs and Specifications:
- RFC 3986: Uniform Resource Identifier (URI) Generic Syntax
- RFC 7230-7237: HTTP/1.1 Semantics and Content
- LOINC Standard (Logical Observation Identifiers Names and Codes): https://loinc.org/
- SNOMED CT (Systematized Nomenclature of Medicine): https://www.snomed.org/
Cloud Platforms and Integration Engines:
- AWS HealthLake Documentation: https://docs.aws.amazon.com/healthlake/
- Azure Health Data Services: https://azure.microsoft.com/en-us/services/health-data-services/
- Google Cloud Healthcare API: https://cloud.google.com/healthcare-api/docs
- Mirth Connect: https://www.nextgen.com/solutions/mirth-connect
- HAPI FHIR: http://hapifhir.io/
Related Posts:
- FHIR Bulk Data API: Exporting EHR Data at Scale
- Healthcare Technology Architecture and Standards
- Zero-Trust Network Architecture for Healthcare Systems
- IEC 62443: Cybersecurity Standards for Healthcare and ICS
Related Posts
