HL7 v2 to FHIR R4 Migration: Modernizing 52 Healthcare Interfaces with Zero Downtime

Executive Summary
Lakeshore Regional Health System operated 52 HL7 v2 interfaces spanning three major version variants (2.3, 2.5, and 2.5.1) across 14 clinical systems. Years of patchwork integrations had produced brittle custom parsers, undocumented message transformations, and a fragile integration layer that consumed 60% of the IT team's maintenance budget. When the organization committed to FHIR R4 as its interoperability standard, they faced a critical constraint: zero tolerance for downtime across any patient-facing workflow.
Nirmitee.io designed and executed a parallel run migration strategy that allowed both HL7 v2 and FHIR R4 messages to flow simultaneously through Mirth Connect as the central translation layer. Over seven months, every interface was migrated, validated against HAPI FHIR reference profiles, and cutover without a single minute of clinical system downtime. The result: 52 modernized FHIR R4 interfaces, 99.5% validation pass rates, and an 85% reduction in integration maintenance effort.
The Problem: Legacy HL7 v2 at Scale
Interface Sprawl and Version Fragmentation
Lakeshore's integration landscape had grown organically over 12 years. The 52 HL7 v2 interfaces connected the Epic EHR, three laboratory information systems (LIS), a radiology information system (RIS), two pharmacy dispensing systems, a bed management platform, a patient portal, and several departmental applications. No two interfaces used the same HL7 v2 version consistently.

The Breakdown by Numbers
| Metric | Before Migration |
|---|---|
| Total interfaces | 52 (HL7 v2.3, v2.5, v2.5.1 mix) |
| Custom parsers | 38 one-off transformation scripts |
| Documented interfaces | 14 of 52 (27%) |
| Monthly integration failures | 23 average incidents |
| Mean time to resolve | 4.2 hours per incident |
| IT staff on integration maintenance | 3.5 FTEs (60% of integration team) |
| Annual maintenance cost | $1.2M |
Why This Was Unsustainable
- Brittle Custom Parsers: 38 hand-written transformation scripts had no unit tests, no documentation, and were maintained by institutional knowledge. When the original developer left, three interfaces broke within a month.
- Version Conflicts: HL7 v2.3 ADT messages from the bed management system used Z-segments that collided with v2.5.1 field definitions from the pharmacy system. Mirth channels had nested conditional logic 200+ lines deep to handle edge cases.
- No Standard Validation: Messages were accepted or rejected based on custom rules that had drifted from any HL7 specification. A lab result could pass through one channel but fail on another for identical content.
- Payer and Regulatory Pressure: CMS Interoperability Rules and TEFCA participation required FHIR R4 capability. Without migration, Lakeshore faced exclusion from regional health information exchanges.
Solution Architecture: Parallel Run with Mirth Connect
Design Principles
The migration strategy was built on three non-negotiable principles:
- Zero downtime: No clinical workflow could be interrupted during migration. Patient care systems must continue operating at all times.
- Parallel validation: Both HL7 v2 and FHIR R4 messages would flow simultaneously during each phase, with automated comparison to ensure data fidelity.
- Rollback capability: Any interface could revert to HL7 v2 within 60 seconds if the FHIR path encountered issues in production.

Architecture Overview
Mirth Connect served as the central integration engine with a dual-path architecture:
- Inbound HL7 v2 Listener: Existing TCP/MLLP listeners continued receiving HL7 v2 messages from source systems with zero configuration changes.
- Translation Channel: A dedicated Mirth channel consumed each HL7 v2 message and produced a corresponding FHIR R4 Bundle using field-level mapping logic.
- Parallel Router: Both the original HL7 v2 message and the translated FHIR R4 Bundle were forwarded to destination systems simultaneously during the validation phase.
- Comparison Engine: A validation service received both outputs, compared them field-by-field, and logged discrepancies to a reconciliation dashboard.
- FHIR Validation: Every translated FHIR resource passed through the HAPI FHIR Validator against US Core R4 profiles before delivery.
// Mirth Connect Channel Architecture (simplified)
//
// Source: TCP Listener (MLLP) → HL7 v2.x messages
// ├── Transformer: HL7v2 → FHIR R4 Bundle
// ├── Destination 1: Original HL7 v2 path (existing)
// ├── Destination 2: FHIR R4 path (new)
// └── Destination 3: Comparison/Validation service
//
// Phase 1: Both paths active, FHIR path is shadow
// Phase 2: FHIR path becomes primary, HL7 v2 is shadow
// Phase 3: HL7 v2 path decommissionedField-Level Mapping: HL7 v2 to FHIR R4
The most technically demanding aspect of the migration was building accurate, comprehensive mappings from HL7 v2 segments to FHIR R4 resources. Each mapping required handling version-specific variations, local extensions, and Z-segment translations.

Core Mapping Table
| HL7 v2 Segment | FHIR R4 Resource | Key Fields Mapped | Complexity |
|---|---|---|---|
| PID (Patient Identification) | Patient | Name, DOB, MRN, SSN, Address, Phone, Race, Ethnicity | Medium |
| PV1 (Patient Visit) | Encounter | Visit number, class, admit/discharge dates, attending physician, location | High |
| OBX (Observation Result) | Observation | Code (LOINC), value, units (UCUM), reference range, status, performer | High |
| OBR (Observation Request) | DiagnosticReport | Order number, test code, specimen, result status, ordering provider | Medium |
| ORC (Common Order) | ServiceRequest | Placer/filler order number, order status, priority, ordering provider | Medium |
| RXA (Pharmacy Administration) | MedicationAdministration | Drug code (NDC/RxNorm), dose, route, site, administrator | High |
| DG1 (Diagnosis) | Condition | ICD-10 code, description, diagnosis type, onset date | Low |
| AL1 (Allergy) | AllergyIntolerance | Allergen code, reaction type, severity, clinical status | Medium |
| NK1 (Next of Kin) | RelatedPerson | Name, relationship, contact info, emergency contact flag | Low |
| IN1 (Insurance) | Coverage | Payer ID, plan name, group number, subscriber, effective dates | High |
Handling Version-Specific Variations
One of the most challenging aspects was that the same logical field could appear in different positions across HL7 v2 versions:
// Example: Patient Race field location varies by version
// HL7 v2.3: PID-10 (Race)
// HL7 v2.5: PID-10 (Race, now coded CE type)
// HL7 v2.5.1: PID-10 (Race, now CWE type with coding system)
//
// FHIR R4 Target: Patient.extension[us-core-race]
// system: urn:oid:2.16.840.1.113883.6.238
// code: mapped from local race table
function mapPatientRace(pid10, sourceVersion) {
const raceMap = {
'W': { code: '2106-3', display: 'White' },
'B': { code: '2054-5', display: 'Black or African American' },
'A': { code: '2028-9', display: 'Asian' },
'I': { code: '1002-5', display: 'American Indian or Alaska Native' },
'P': { code: '2076-8', display: 'Native Hawaiian or Other Pacific Islander' }
};
let raceCode;
if (sourceVersion === '2.3') {
raceCode = pid10; // Simple text field
} else {
raceCode = pid10.split('^')[0]; // CE/CWE coded element
}
return raceMap[raceCode] || { code: '2131-1', display: 'Other Race' };
}Terminology Mapping
Beyond structural mapping, terminology translation was essential:
- Local lab codes → LOINC: Lakeshore used 1,200+ local lab codes. We built a mapping table validated by the laboratory director and mapped 94% to LOINC codes automatically. The remaining 6% were manually curated.
- Local drug codes → RxNorm/NDC: Pharmacy systems used a mix of NDC-10 and NDC-11 formats with local extensions. All were normalized to RxNorm concept IDs.
- Units → UCUM: Lab result units like "mg/dl", "MG/DL", and "milligrams per deciliter" were all normalized to UCUM standard codes (
mg/dL). - Local identifiers → NPI: Provider identifiers were mapped from local physician IDs to National Provider Identifiers for FHIR Practitioner resources.
FHIR Validation with HAPI FHIR Validator
Every translated FHIR resource was validated before delivery to ensure conformance with US Core R4 profiles. We deployed the HAPI FHIR Validator as a microservice called by Mirth Connect after each translation.

Validation Pipeline
- Structural Validation: Verify the FHIR JSON conforms to the R4 schema (required fields, correct data types, valid references).
- Profile Validation: Validate against US Core R4 profiles (e.g., us-core-patient requires race, ethnicity, and birth sex extensions).
- Terminology Validation: Confirm that coded elements use valid codes from the specified code systems (LOINC, SNOMED CT, RxNorm, ICD-10-CM).
- Business Rule Validation: Custom rules for Lakeshore-specific requirements (e.g., all Encounter resources must reference an Organization, all Observation resources must have a performer).
// HAPI FHIR Validator Integration (Java)
FhirContext ctx = FhirContext.forR4();
FhirValidator validator = ctx.newValidator();
// Load US Core profiles
NpmPackageValidationSupport npmSupport = new NpmPackageValidationSupport(ctx);
npmSupport.loadPackageFromClasspath("classpath:hl7.fhir.us.core-6.1.0.tgz");
ValidationSupportChain chain = new ValidationSupportChain(
new DefaultProfileValidationSupport(ctx),
npmSupport,
new InMemoryTerminologyServerValidationSupport(ctx),
new CommonCodeSystemsTerminologyService(ctx)
);
FhirInstanceValidator instanceValidator = new FhirInstanceValidator(chain);
validator.registerValidatorModule(instanceValidator);
// Validate each resource
ValidationResult result = validator.validateWithResult(fhirBundle);
for (SingleValidationMessage msg : result.getMessages()) {
if (msg.getSeverity() == ResultSeverityEnum.ERROR) {
log.error("Validation error: {} at {}", msg.getMessage(), msg.getLocationString());
}
}Validation Results by Phase
| Phase | Resources Validated | Pass Rate | Common Issues |
|---|---|---|---|
| ADT (Phase 1) | 45,000 | 97.2% | Missing race/ethnicity extensions, invalid phone formats |
| Lab (Phase 2) | 128,000 | 98.8% | Unmapped LOINC codes, UCUM unit mismatches |
| Orders (Phase 3) | 67,000 | 99.1% | Missing performer references, order status mapping |
| Clinical Docs (Phase 4) | 31,000 | 99.5% | Document type coding, attachment MIME types |
Phase-by-Phase Migration
The migration was executed in four phases over seven months, ordered by interface complexity and clinical risk.

Phase 1: ADT Interfaces (Month 1-2)
Admit-Discharge-Transfer messages were migrated first because they are the backbone of patient identity and encounter management. 12 ADT interfaces were converted, producing Patient, Encounter, Location, and RelatedPerson resources.
- Interfaces migrated: 12
- FHIR resources produced: Patient, Encounter, Location, RelatedPerson, Coverage
- Parallel run duration: 3 weeks
- Key challenge: Merging duplicate patient records across systems into a single FHIR Patient resource with multiple identifiers
Phase 2: Laboratory Interfaces (Month 2-4)
Lab interfaces were the highest volume, processing 4,200+ messages daily. 18 interfaces were migrated, producing Observation, DiagnosticReport, Specimen, and ServiceRequest resources.
- Interfaces migrated: 18
- Daily message volume: 4,200+
- FHIR resources produced: Observation, DiagnosticReport, Specimen, ServiceRequest
- Parallel run duration: 4 weeks
- Key challenge: Mapping 1,200 local lab codes to LOINC with clinical validation by lab director
Phase 3: Order Interfaces (Month 4-6)
Order entry and results interfaces required careful coordination with clinical workflow. 14 interfaces were migrated, covering medication orders, procedure orders, and referrals.
- Interfaces migrated: 14
- FHIR resources produced: ServiceRequest, MedicationRequest, MedicationAdministration, Task
- Parallel run duration: 3 weeks
- Key challenge: Bidirectional order status synchronization between HL7 v2 ORC segments and FHIR Task resources
Phase 4: Clinical Documents (Month 6-7)
The final phase covered CDA documents, clinical notes, and specialized departmental interfaces. 8 interfaces were migrated, producing DocumentReference, Composition, and Binary resources.
- Interfaces migrated: 8
- FHIR resources produced: DocumentReference, Composition, Binary, Provenance
- Parallel run duration: 2 weeks
- Key challenge: Converting embedded RTF/PDF documents to FHIR Binary resources with correct MIME type coding

FHIR Resource Coverage
By the end of the migration, Lakeshore's integration layer produced 22 distinct FHIR R4 resource types, covering the full US Core required resource set plus additional resources needed for operational workflows.

Parallel Run Monitoring
The parallel run strategy required real-time monitoring to ensure data fidelity between the HL7 v2 and FHIR R4 paths. We built a custom monitoring dashboard that compared every message pair and flagged discrepancies.

Monitoring Metrics
- Message pair match rate: Percentage of message pairs where HL7 v2 and FHIR R4 outputs contained semantically equivalent data
- Field-level discrepancy rate: Number of individual field mismatches per 1,000 messages
- Latency delta: Processing time difference between the HL7 v2 path and the FHIR R4 path (target: <200ms additional latency)
- Validation failure rate: Percentage of FHIR resources that failed HAPI FHIR validation
- Rollback events: Number of times the system automatically reverted to the HL7 v2 path due to FHIR path errors
Cutover Decision Criteria
Each interface was cleared for FHIR-primary cutover only after meeting all of the following thresholds during the parallel run:
| Criterion | Threshold | Measurement Period |
|---|---|---|
| Message pair match rate | ≥ 99.0% | 7 consecutive days |
| FHIR validation pass rate | ≥ 99.0% | 7 consecutive days |
| Additional latency | < 200ms p95 | 7 consecutive days |
| Zero critical discrepancies | 0 patient safety fields mismatched | 14 consecutive days |
| Clinical sign-off | Department head approval | Before cutover |
Results
| Metric | Before | After | Improvement |
|---|---|---|---|
| Interfaces | 52 HL7 v2 (mixed versions) | 52 FHIR R4 (unified) | Single standard |
| Custom parsers | 38 | 0 | 100% eliminated |
| FHIR validation pass rate | N/A | 99.5% | Standard conformance |
| Monthly integration incidents | 23 | 3 | 87% reduction |
| Mean time to resolve | 4.2 hours | 0.8 hours | 81% faster |
| Integration maintenance FTEs | 3.5 | 0.5 | 85% reduction |
| Annual maintenance cost | $1.2M | $180K | 85% savings |
| Documented interfaces | 14 of 52 (27%) | 52 of 52 (100%) | Full documentation |
| Clinical system downtime | N/A | 0 minutes | Zero downtime achieved |
| Migration duration | N/A | 7 months | On schedule |
Technology Stack
| Component | Technology | Role |
|---|---|---|
| Integration Engine | Mirth Connect 4.4 | Message routing, transformation, parallel run orchestration |
| FHIR Server | HAPI FHIR JPA Server 6.8 | FHIR resource storage and RESTful API |
| FHIR Validation | HAPI FHIR Validator | US Core R4 profile validation |
| Terminology Server | HAPI FHIR + custom mappings | LOINC, SNOMED CT, RxNorm, ICD-10 lookups |
| Database | PostgreSQL 15 | FHIR resource persistence, audit logs |
| Monitoring | Grafana + Prometheus | Real-time parallel run dashboards, alerting |
| Message Queue | Apache Kafka | Async message buffering between parallel paths |
| Infrastructure | Docker + Kubernetes | Container orchestration, horizontal scaling |
| CI/CD | GitHub Actions | Automated testing, Mirth channel deployment |
Migration Timeline
| Month | Phase | Activities | Interfaces |
|---|---|---|---|
| Month 1 | Discovery & Planning | Interface inventory, mapping analysis, architecture design, environment setup | 0 (planning) |
| Month 1-2 | Phase 1: ADT | Patient, Encounter, Location mappings. Parallel run validation. ADT cutover. | 12 |
| Month 2-4 | Phase 2: Laboratory | Observation, DiagnosticReport mappings. LOINC terminology mapping. Lab cutover. | 18 |
| Month 4-6 | Phase 3: Orders | ServiceRequest, MedicationRequest mappings. Bidirectional order sync. Orders cutover. | 14 |
| Month 6-7 | Phase 4: Clinical Docs | DocumentReference, Composition mappings. CDA conversion. Final cutover. | 8 |
| Month 7 | Decommission | HL7 v2 shadow paths removed. Legacy parsers archived. Documentation finalized. | 52 (complete) |
Lessons Learned
1. Invest in Terminology Mapping Early
Terminology mapping consumed 40% of the total project effort. The 1,200 local lab codes required clinical validation that could not be automated. Starting terminology work in Month 1 — before any interface development — was critical to staying on schedule. Organizations planning similar migrations should allocate dedicated clinical informaticist time for terminology curation.
2. Parallel Run Is Non-Negotiable for Zero Downtime
The parallel run strategy added complexity and infrastructure cost, but it was the only approach that provided both safety and confidence. Every interface that passed the parallel run criteria cut over without incident. The two interfaces where we initially considered skipping the parallel run (low-volume departmental feeds) were the ones that revealed the most mapping edge cases during validation.
3. Version-Specific Edge Cases Are the Real Work
The core HL7 v2 to FHIR R4 mapping is well-documented by HL7 International. The real engineering effort was handling Lakeshore-specific variations: Z-segments, local code tables, non-standard field usage, and version-specific quirks in how different source systems populated the same HL7 v2 fields. Budget 3x the time you think you need for edge case handling.
4. Mirth Connect Channel Design Matters
We initially built monolithic Mirth channels that handled entire message types end-to-end. This became unmaintainable. Refactoring into a modular channel architecture — with separate channels for segment parsing, terminology lookup, FHIR resource assembly, and validation — dramatically improved testability and debugging. Each channel could be tested independently with recorded message fixtures.
5. FHIR Validation Catches What Testing Misses
Integrating HAPI FHIR validation into the pipeline (not just as a post-hoc check) caught hundreds of issues that functional testing alone would have missed. Structural problems like missing required extensions, invalid code system URIs, and malformed references were caught automatically. Make validation a gate, not a report.
6. Clinical Stakeholder Buy-In Requires Visible Progress
The migration dashboard that showed real-time interface status, validation rates, and cutover progress was not originally planned. It was added after Month 2 when clinical leadership expressed concern about timeline risk. That dashboard became the single most important communication tool for the project, presented weekly at the steering committee. Build it from Day 1.
Conclusion
Migrating 52 HL7 v2 interfaces to FHIR R4 is not a trivial undertaking, but with the right strategy — parallel runs, Mirth Connect as the translation layer, HAPI FHIR validation, and phased rollout — it can be executed with zero clinical downtime and predictable outcomes. Lakeshore Regional Health System now operates on a unified FHIR R4 integration layer that is standards-compliant, maintainable, and ready for TEFCA participation.
The 85% reduction in maintenance effort alone justified the investment within the first year. More importantly, the organization now has a modern interoperability foundation that can support new use cases — patient access APIs, payer data exchange, clinical decision support — without building custom interfaces from scratch.
Contact Nirmitee.io to discuss your HL7 v2 to FHIR R4 migration strategy. We bring hands-on experience with Mirth Connect, HAPI FHIR, and the parallel run methodology that eliminates downtime risk.
Was this case study helpful?


