HL7 to FHIR Migration: A Practical Guide

Most hospitals run FHIR on the outside and HL7 v2 on the inside. That split is exactly what pushes teams toward moving from a legacy EMR to a FHIR-first architecture. If you are planning an HL7 to FHIR migration, you are not really replacing HL7. You are building a bridge between two very different eras of healthcare data. And that bridge has to work for years.
This guide is for developers and integration engineers who actually have to make that bridge work. It is technical, honest, and I am not going to pretend this is easy.
Why HL7 v2 is still everywhere
Let us be honest. HL7 v2 has been running hospitals since the late 1980s. Lab interfaces, ADT feeds, order management, result reporting, all of it runs on v2. It is ugly, but it works. And because it works, nobody is going to rip it out.
The format itself is painfully simple. It uses pipe characters (|) to separate fields and caret signs (^) to separate pieces inside a field. A real HL7 v2 message looks something like this:
MSH|^~\&|LAB|ABC|EHR|XYZ|202506130930||ORU^R01|12345|P|2.4|
PID|1||1001^^^MRN||Doe^John||19800101|M
OBX|1|NM|GLU^Glucose||110|mg/dL|70-99|H
Every vendor customizes these messages in their own way. But the core idea is the same. HL7 to FHIR migration is not about throwing v2 away. It is about getting v2 and FHIR to talk to each other. If you are new to FHIR, check out the official FHIR specification first.
The core HL7 to FHIR migration mapping challenge
Here is where it gets tricky. HL7 v2 segments like PID, OBR, OBX, and MSH do not map cleanly to FHIR resources like Patient, DiagnosticReport, and Observation. You cannot just match fields one to one.
Let me give you an example. An OBX segment carries a lab result. 
If you just copy fields without understanding what they mean clinically, you will lose context. That is why a good HL7 to FHIR migration always involves both developers and domain experts. You cannot do this alone.
Middleware options
You can write custom code to convert v2 messages into FHIR resources. But most teams start with existing middleware. Here is a quick comparison of the most common options:
| Middleware | Type | Best For | Key Trade Off |
|---|---|---|---|
| Mirth Connect | Open source | Teams with budget constraints and good in house HL7 expertise | Free but requires setup and maintenance |
| Rhapsody | Commercial enterprise | Large hospitals needing audit trails and vendor support | Expensive but production ready |
| Redox | API first platform | Startups and apps that want to skip middleware management | Least control but fastest to market |
Mirth Connect is open source and very popular. It gives you a visual way to build channels that listen for v2 messages, parse them, and output FHIR bundles. Rhapsody is a commercial engine with strong enterprise features like audit logs and high availability. Redox takes a different approach. They give you a unified API and handle the v2 to FHIR conversion behind the scenes.
So when should you use an engine versus custom code? Engines give you built in monitoring, maintenance, and connectors. Custom code gives you full control but adds a lot of long term overhead. For most hospitals, a middleware engine is the safer bet. You can look at the Mirth Connect documentation to see how it handles HL7 to FHIR transformations.
Running both in parallel
The realistic migration path is not a big bang cutover. It is a parallel run that lasts for months.
Here is a typical scenario. An EHR exposes a FHIR API to external apps. But its internal lab interface still sends HL7 v2 messages. A middleware layer maps incoming v2 lab results into FHIR Observations in real time. Both systems run live side by side. The external apps query the FHIR API. The internal workflows keep using v2. Nobody even notices the change.
During parallel run, you need data reconciliation. That means periodically comparing a sample of v2 messages with their transformed FHIR resources. Check if patient identifiers match. See if all observation values are there. Find out if any fields got dropped. You also need validation on the FHIR side. The Observation resources must pass FHIR profile validation before you store them.
Parallel run gives you confidence. When you finally retire the old v2 interface, you know the FHIR side has already been handling live traffic for months.
Common pitfalls
Do not assume v2 messages are consistent. They are not. Every vendor customizes. One hospital might send the patient name in PID-5 as Last^First. Another might send First Last without a caret. Your parser has to handle both.
Z-segments are another headache. These are custom segments that vendors add to carry proprietary data. Standard HL7 v2 parsers will ignore them. But if those Z-segments contain clinical data you need in FHIR, you have to write custom logic to extract and map them.
Character encoding and delimiter issues are very common. The default encoding in HL7 v2 is often not UTF-8. You may see ASCII with extended characters that break JSON serialization in FHIR. And some vendors change the field delimiter from pipe to something else.
Finally, be ready to lose some data. Not every v2 field has a FHIR equivalent. You have to decide whether to drop that data, store it in an extension, or put it in a placeholder like Observation.note. Each choice has trade offs.
FAQs
Does migrating to FHIR mean replacing HL7 v2 entirely?
No. Most hospitals run FHIR externally while internal lab interfaces and ADT feeds keep running on HL7 v2. The realistic goal is building a bridge between the two, not ripping v2 out of the hospital's existing workflow.
Why doesn't HL7 v2 map cleanly to FHIR resources?
HL7 segments like PID, OBR, and OBX don't correspond one-to-one with FHIR resources like Patient or Observation. Mapping a lab result's abnormal flag or reference range into the right FHIR fields requires clinical judgment, not just copying fields across.
What are the main middleware options for HL7 to FHIR conversion?
Mirth Connect, open source but needs in-house HL7 expertise to set up and maintain; Rhapsody, a commercial engine with enterprise features like audit trails and high availability; and Redox, an API-first platform that handles the v2-to-FHIR conversion behind the scenes with less control but faster time to market.
How long should a parallel run between HL7 v2 and FHIR last?
A realistic migration runs over months, not a single cutover. In one client project, HL7 v2 and FHIR ran in parallel for eight months, including periodic reconciliation comparing v2 messages against their transformed FHIR resources.
What are common pitfalls in an HL7 to FHIR migration?
Inconsistent vendor formatting of v2 messages, custom Z-segments that standard parsers ignore but may carry needed clinical data, character encoding issues that can break FHIR's JSON serialization, and fields that have no clean FHIR equivalent at all.
What should happen to v2 data that has no FHIR equivalent?
Each case needs a deliberate decision: drop the data, store it in a FHIR extension, or place it somewhere like Observation.note. Each of those choices carries trade-offs that should be made on purpose, not by default.
Conclusion
HL7 to FHIR migration is not a checkbox. It is a commitment that shapes every integration decision, from your middleware choice to your field mapping logic to your parallel run validation scripts. The teams that get this right early move faster later.
At Aishco, we understand these problems across hospital lab integrations, EHR migrations, and real time v2 to FHIR conversions. Knowing the theory is different from walking the path.
If you are planning a migration, check out our guides on FHIR vs HL7, What Is FHIR, and Integrating EHR Systems with FHIR. You can also see how Aishco Solutions helps healthcare teams with integration strategy and custom middleware development. Go in with your eyes open.



