mdatool
Healthcare Data Dictionary for the Modern Data Stack
LibraryBlogPricing
mdatool
mdatool

The healthcare data dictionary for dbt, Snowflake, Databricks, and BigQuery. 100,000+ ISO-11179 standard terms, free SQL tools, and AI data modeling.

HIPAA-AlignedEnterprise Ready

Tools

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

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 teams.

HomeBlogHealthcare 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

📋HL7 Parser

Parse and validate HL7 v2 messages with segment-level field breakdowns.

Try it free

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

More in Healthcare Standards

ISO-11179 Naming Convention Complete Guide for Healthcare Data Engineers

Inconsistent column names are the single most preventable source of confusion in healthcare data warehouses. ISO-11179 solves it — and it is the naming standard behind every well-designed claims, clinical, and member schema. Here is the complete guide.

Read more

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

Get weekly healthcare data engineering tips

Practical guides on data modeling, SQL standards, and healthcare domain conventions — straight to your inbox.

No spam. Unsubscribe any time.

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