Written for the integration architect who owns, or is scoping, a v2-to-FHIR programme in a live NHS estate. Generic conversion content is saturated, so this piece wins only on the UK-Core-specific slice: identifiers, bindings and the four estate decisions generic guides can't make. The merge-message treatment and the "clinician reads both, draws the same conclusion" quality test are the credibility anchors. Builds on the HL7 v2 message types and FHIR resources explainers, links to the terminology governance and UK Core conformance pieces as siblings, and hangs off the standards map as its hub.
The proof of concept goes well. A converter runs over a folder of sample messages, clean FHIR comes out the other side, and the project board sees a green tick. Three months into production, the picture is different: the PAS populates a field the samples never used, a departmental system speaks in Z-segments nobody documented, result codes arrive from a local vocabulary the target profile has never heard of, and one afternoon an A40 merge message quietly asks the pipeline a question nobody had decided how to answer.
None of this means the project chose badly. It means v2-to-FHIR conversion is a translation discipline, not a file format change, and the difference is exactly what this guide covers.
In brief
HL7 v2 and FHIR describe the world differently: v2 announces events with implicit context, FHIR states resources with explicit structure, so one message typically becomes several linked resources and the mapping starts from the trigger event, not the segment. ADT traffic maps principally to Patient and Encounter with a lifecycle to respect and a merge case to treat with fear; ORU traffic maps to DiagnosticReport and Observations where units, statuses and codes carry the clinical meaning. UK Core then raises the bar from "valid FHIR" to "NHS FHIR": identifier rules, mandatory elements, terminology bindings. And a set of decisions (conflict authority, Z-segment policy, identifier strategy, extension-versus-drop) belongs to your estate, not the spec; naming them upfront is most of the work.
A translation problem, not a format problem
The two standards don't just differ in syntax; they differ in worldview. A v2 message is an event with context smeared across segments: the PV1 implies an encounter, the PID implies a patient, and the receiving system is trusted to know the local conventions. FHIR is the opposite: explicit resources, explicit references, explicit statuses, nothing implied.
Two consequences drive everything below. First, cardinality: one v2 message fans out into several FHIR resources (a Patient, an Encounter, Observations, references between them), so conversion is construction, not substitution. Second, context reconstruction: the information FHIR wants stated explicitly often exists in v2 only as convention, which is why a generic mapping gets you most of the way and your estate's dialects decide the rest. Published baseline mappings exist and are genuinely useful; treat them as the starting point they are, not as the finished product they aren't.
Start from the trigger event, not the segment
The organising unit of v2 is the trigger event in MSH-9, and it should be the organising unit of your mapping too. An ADT^A01 doesn't mean "here are some segments"; it means "an admission happened", and the correct output is an Encounter coming into being (status in-progress, class inpatient, period started) alongside a Patient update. An A03 means that Encounter finishing. An A08 means "something about this patient or visit changed", which is why it's both the highest-volume message in most Trusts and the one requiring the most careful update semantics.
Mapping segment-by-segment produces structurally plausible FHIR with the wrong lifecycle underneath. Mapping trigger-by-trigger produces resources whose statuses and periods tell the true story, and it gives every mapping decision a home: for this event, these resources, these transitions.
Mapping ADT: admissions, transfers and the merge problem
For the core ADT set, the shape is consistent: PID drives the Patient (identity, demographics), PV1 drives the Encounter (class, location, responsible clinician, period), and transfers (A02) update the Encounter's location rather than minting anything new. The discipline is idempotency and update semantics: the same admission arriving twice must not create two Encounters, which is where a deterministic identifier strategy (more below) earns its keep.
Then there's A40, the merge, which deserves its own paragraph and your fear. A merge asserts that two patient identities are one person, and in FHIR terms that touches identifiers, the link between records, and by implication every resource referencing the retired identity. The honest guidance: do not let a converter handle merges as if they were routine updates. Map the event faithfully, but route it through a controlled path with human-visible handling, because a mishandled merge is the rare integration error that corrupts downstream systems for years rather than days.
Mapping ORU: results into Observations that mean something
An ORU^R01 carries a report's worth of structure: the OBR describes what was requested and reported, each OBX carries one observation. The natural FHIR shape mirrors it: a DiagnosticReport grouping Observations, references back to the Patient and, where the context exists, the Encounter and the ServiceRequest that asked.
The clinical meaning lives in the details that casual conversions flatten. Value types matter: a numeric OBX becomes a valueQuantity with a proper unit (UCUM is the destination worth insisting on), a coded OBX becomes a CodeableConcept whose code and system both survive the journey. Status matters just as much: preliminary, final and corrected results map to Observation and DiagnosticReport statuses, and a pipeline that flattens "corrected" into "final" has changed clinical meaning while validating perfectly. Reference ranges, abnormal flags and the grouping of panels into their members complete the set. This is where conversion quality is genuinely measurable: pick ten real results and ask whether a clinician reading the FHIR would draw the same conclusion as one reading the v2.
The UK Core layer: identifiers, profiles and bindings
Everything above produces valid FHIR. The NHS target is stricter: UK Core, which adds three demands to the converted output. Identity first: the NHS number carried in its defined identifier slot with verification status handled the agreed way, which means your mapping must know where identity truth comes from in your v2 traffic and how much to trust it. Structure second: the relevant UK Core profiles make elements mandatory that base FHIR leaves optional, so the mapping must source them or the output fails validation regardless of how faithful the translation was. Terminology third, and hardest: coded elements are bound to value sets, and the local codes riding in your v2 messages (result codes especially) need translating through governed concept maps at the boundary, not passed through on hope. This is where the conversion pipeline meets the terminology machinery covered elsewhere on this blog, and estates that treat them as separate projects discover at integration testing that they were one project all along.
The decisions the spec won't make for you
Four decisions recur in every serious v2-to-FHIR programme, and no published mapping can make them, because they're statements about your estate. Authority on conflict: when a v2 field disagrees with what the FHIR side already holds, which source wins, per field, in writing. Z-segment policy: for each local segment, an explicit choice to map it, carry it as a documented extension, or park it in an exception flow, because the one forbidden option is silently discarding content someone once considered clinically worth sending. Identifier strategy: deterministic resource identities derived from message keys, so replays and duplicates converge on the same resources instead of multiplying them; this single decision is most of what "idempotent" means in practice. And representation gaps: when v2 carries something the target profile has no home for, the choice between a governed extension and a documented omission is a clinical-safety conversation, not a developer default.
Write these four down before the first mapping workshop and the workshops get shorter. Skip them and they get made anyway, silently, one edge case at a time.
A pipeline that holds up in production
Assembled, the production shape looks like this: v2 arrives (MLLP from the estate, typically), is parsed as structure rather than string, and is routed by trigger event to its mapping. Conversion runs as a baseline transform plus your estate's dialect layer (in WeHub Studio terms, the HL7 Operation does the parsing and the FHIR Converter's HL7-to-FHIR conversion provides the baseline the local mappings shape). The output then passes the terminology boundary ($translate for local codes, $validate-code against the bound value sets) and profile validation against pinned UK Core, before delivery. Around the spine, the habits that decide whether it survives contact with production: per-stage exception routes with named owners, so a parse failure, a mapping gap and a terminology miss land in different queues; reprocessing as a first-class operation, because upstream will resend; and reconciliation counts per feed, so silence and success stop looking identical.
The bottom line
A v2-to-FHIR programme succeeds on three disciplines, none of them exotic: map by trigger event so lifecycles survive, treat UK Core (identifiers, mandatory elements, bindings) as the real target rather than base FHIR, and make the four estate decisions explicitly before they make themselves. The first step is small and revealing: take one day of real ADT and ORU traffic from your engine, run it against a baseline mapping, and catalogue everything that falls out. That catalogue, not the sample folder, is your actual project scope.



