mdatool
LibraryBlogPricing
mdatool
mdatool

Healthcare data architecture platform for data engineers, architects, and analysts building modern health systems.

HIPAA-AlignedEnterprise Ready

Tools

  • SQL Linter
  • DDL Converter
  • Bulk Sanitizer
  • Naming Auditor
  • Name Generator
  • AI Data Modeling
  • HCC Calculator

Library

  • Glossary
  • Guides
  • Blog

Company

  • About
  • Contact
  • Pricing

Account

  • Sign Up Free
  • Sign In
  • Upgrade to Pro
  • Dashboard

Legal

  • Privacy Policy
  • Terms of Service

© 2026 mdatool. All rights reserved.

Built for healthcare data engineers & architects.

BlogHealthcare StandardsHL7 v2 to FHIR R4 Mapping Guide: Segment-by-Segment Translation with Examples
Healthcare Standards

HL7 v2 to FHIR R4 Mapping Guide: Segment-by-Segment Translation with Examples

A practical segment-by-segment guide to translating HL7 v2 messages (ADT, ORU, DG1, AL1) into FHIR R4 resources — with real JSON examples and the common pitfalls that break translation pipelines.

mdatool Team·April 29, 2026·14 min read
HL7FHIRhealthcare interoperabilitydata mappinghealthcare data engineering

Why HL7 v2 to FHIR Migration Is Harder Than It Looks

📋

Free Tool

Parse this HL7 message →

HL7 v2 has been the lingua franca of healthcare data exchange since 1989. FHIR R4 is where the industry is heading, driven by CMS interoperability rules and the 21st Century Cures Act. Translating between them is not a simple format conversion — the two standards have fundamentally different data models.

HL7 v2 is a pipe-delimited message format organized around clinical events. FHIR is a RESTful API standard organized around resources (Patient, Observation, MedicationRequest). The same clinical fact is expressed differently in each.


HL7 v2 Message Structure Refresher

MSH|^~\&|SENDING_APP|SENDING_FAC|RECV_APP|RECV_FAC|20260115120000||ADT^A01|MSG001|P|2.5.1 PID|1||MRN12345^^^HOSP^MR||SMITH^JOHN^A||19820304|M|||123 MAIN ST^^CHICAGO^IL^60601^USA PV1|1|I|3N^301^A||||1234567890^JONES^SARAH^^^DR.||||||||||ADM001

Key segments: MSH (header), PID (patient), PV1 (visit), OBX (observation), OBR (lab order), AL1 (allergy), DG1 (diagnosis).


ADT^A01 (Admit) → FHIR Encounter + Patient

PID Segment → FHIR Patient

PID|1||MRN12345^^^HOSP^MR||SMITH^JOHN^A||19820304|M
{
  "resourceType": "Patient",
  "identifier": [{ "use": "official", "value": "MRN12345" }],
  "name": [{ "use": "official", "family": "Smith", "given": ["John", "A"] }],
  "birthDate": "1982-03-04",
  "gender": "male"
}

Key mappings:

  • PID-3 → Patient.identifier
  • PID-5 → Patient.name (HL7 family^given^middle → FHIR separate fields)
  • PID-7 → Patient.birthDate (YYYYMMDD → YYYY-MM-DD)
  • PID-8 → Patient.gender (M/F/U → male/female/unknown)

PV1 Segment → FHIR Encounter

{
  "resourceType": "Encounter",
  "status": "in-progress",
  "class": { "code": "IMP", "display": "inpatient encounter" },
  "subject": { "reference": "Patient/MRN12345" },
  "participant": [{ "individual": { "display": "Dr. Sarah Jones" } }],
  "identifier": [{ "value": "ADM001" }]
}

PV1-2 patient class: I=IMP (inpatient), O=AMB (ambulatory), E=EMER (emergency).


ORU^R01 (Lab Result) → FHIR Observation

OBX Segment → FHIR Observation

OBX|1|NM|2093-3^CHOLESTEROL^LN||185|mg/dL^mg/dL^UCUM|<200||||F|||20260115090000
{
  "resourceType": "Observation",
  "status": "final",
  "code": { "coding": [{ "system": "http://loinc.org", "code": "2093-3", "display": "Cholesterol" }] },
  "subject": { "reference": "Patient/MRN12345" },
  "valueQuantity": { "value": 185, "unit": "mg/dL" },
  "referenceRange": [{ "text": "<200" }]
}

Key OBX mappings:

  • OBX-2 (value type): NM=valueQuantity, ST=valueString, CE=valueCodeableConcept
  • OBX-3 (identifier): → Observation.code — typically a LOINC code
  • OBX-5 (value): → Observation.value[x]
  • OBX-8 (abnormal flags): A=Abnormal, H=High, L=Low, N=Normal
  • OBX-11 (status): F=final, P=preliminary, C=corrected

DG1 Segment → FHIR Condition

DG1|1|ICD10|I10^ESSENTIAL HYPERTENSION^ICD10|20260115|A
{
  "resourceType": "Condition",
  "clinicalStatus": { "coding": [{ "code": "active" }] },
  "code": {
    "coding": [{ "system": "http://hl7.org/fhir/sid/icd-10-cm", "code": "I10", "display": "Essential hypertension" }]
  },
  "subject": { "reference": "Patient/MRN12345" },
  "onsetDateTime": "2026-01-15"
}

AL1 Segment → FHIR AllergyIntolerance

AL1|1|DA^Drug Allergy|PENICILLIN^PENICILLIN^L|SV^Severe|HIVES~ANAPHYLAXIS|19950601
{
  "resourceType": "AllergyIntolerance",
  "category": ["medication"],
  "criticality": "high",
  "code": { "text": "Penicillin" },
  "patient": { "reference": "Patient/MRN12345" },
  "reaction": [{ "manifestation": [{ "coding": [{ "display": "Hives" }] }], "severity": "severe" }]
}

Common Translation Pitfalls

1. Date format conversion — HL7 uses YYYYMMDDHHMMSS, FHIR uses ISO 8601 (YYYY-MM-DDThh:mm:ss).

2. Repeating fields — HL7 uses ~ to separate repetitions. Each maps to a separate FHIR array element.

3. Null vs missing — HL7 uses "" to explicitly null a field. FHIR uses absence of a field. Handle these explicitly.

4. Code system mapping — HL7 v2 often uses local facility codes. FHIR prefers LOINC, SNOMED CT, RxNorm, ICD-10. Normalize local codes in your translation layer.

5. Component separators — HL7 uses ^ for components and & for subcomponents. FHIR has explicit fields for each — don't flatten them.


Testing Your HL7 → FHIR Translation

  1. Parse the raw HL7 message — validate structure. Use the HL7 Parser tool to validate incoming v2 messages.
  2. Map each segment — apply translation field by field.
  3. Validate the FHIR output — run against the hl7.org FHIR validator.
  4. Round-trip test — convert HL7→FHIR and back, verify no data loss.
  5. Edge cases — test empty fields, repeating fields, unknown codes, and malformed dates.

Related Guides

HL7 & FHIR Interoperability

HL7 message formats, FHIR resources, and healthcare data exchange standards.

Read Guide

Free Tools

Free HL7 v2 Parser

Paste any HL7 v2 message and decode every segment into labeled fields.

Try it free

Ready to improve your data architecture?

Free tools for DDL conversion, SQL analysis, naming standards, and more.

Get Started Free

On this page

  • Why HL7 v2 to FHIR Migration Is Harder Than It Looks
  • HL7 v2 Message Structure Refresher
  • ADT^A01 (Admit) → FHIR Encounter + Patient
  • PID Segment → FHIR Patient
  • PV1 Segment → FHIR Encounter
  • ORU^R01 (Lab Result) → FHIR Observation
  • OBX Segment → FHIR Observation
  • DG1 Segment → FHIR Condition
  • AL1 Segment → FHIR AllergyIntolerance
  • Common Translation Pitfalls
  • Testing Your HL7 → FHIR Translation

Share

Share on XShare on LinkedIn

Engineering Tools

Convert DDL, lint SQL, and audit naming conventions — free.

Explore Tools