NEWFree ROI Calculators — quantify what prior auth and siloed data are costing your organization.Prior Auth ROI Siloed Data ROI
HL7 v2Guide11 min read

HL7 Message Structure: Segments, Fields, Components, and Delimiters

HL7 v2 messages are built from a hierarchical set of building blocks: segments contain fields, fields contain components, and components contain sub-components. Each level is separated by a specific delimiter character, creating a compact, human-readable format that is efficient to parse and resilient to local variation.

Segments → Fields → Components → Sub-components

The HL7 v2 message framework is hierarchical, consisting of named building blocks called elements. Understanding the nesting structure is essential to reading, parsing, and generating valid messages.

Segments are the top-level logical units. Every segment begins with a three-character identifier (the segment ID) followed by the field separator, then one or more fields. Common segments include:

  • MSH: Message header (required; always first)
  • PID: Patient identification
  • OBR: Observation request (order)
  • OBX: Observation result (single result value)
  • ERR: Error information

Each segment is encoded on a single line, terminated by a line break (carriage return, line feed, or carriage return + line feed).

Fields are named data elements within a segment, identified by sequence number. For example, PID-3 is the patient identifier field within the PID segment. Fields are separated by the field-separator character (default: |). A field may be:

  • Simple: A string value like "John" or "12345"
  • Complex (composite): A structured data type like XPN (extended person name), which is itself composed of named components

Components are named sub-elements within a complex field. The PID-5 field (patient name) is an XPN data type with components:

  • XPN-1: Family name
  • XPN-2: Given name
  • XPN-3: Middle name
  • XPN-4: Name prefix
  • XPN-5: Name suffix

Components are separated by the component-separator character (default: ^).

Sub-components are named sub-elements within a component, separated by the sub-component-separator character (default: &). For example, the CX data type (extended composite ID with check digit) has component CX.4 (assigning authority), which has sub-components:

  • CX.4.1: Namespace ID
  • CX.4.2: Universal ID
  • CX.4.3: Universal ID type

This four-level hierarchy (segment, field, component, sub-component) allows HL7 v2 to represent rich clinical data efficiently while remaining lightweight and easy to transmit over legacy systems.

Delimiters Explained

HL7 v2 uses five special characters as delimiters. The standard set is |^~&, defined in the MSH segment's encoding-characters field. Each delimiter serves a specific purpose:

DelimiterNameASCIIDefaultPurpose
``Field separator124`
^Component separator94^Separates components within a field
~Repetition separator126~Separates repetitions of a field
``Escape character92``Escapes special characters within field values
&Sub-component separator38&Separates sub-components within a component

Field separator (|): Divides the fields of a segment. Every segment uses this character after the segment ID and between each field.

Component separator (^): Divides components within a complex (composite) field. Not used in simple fields. For example, in the XPN data type:

John^Mary^Jr^Dr^

Here, John is the family name, Mary is the given name, Jr is the suffix, Dr is the prefix (note the trailing ^ indicates an empty component for the middle name).

Repetition separator (~): Allows a field to repeat, carrying multiple values. For example, a patient may have multiple identifiers:

12345^MRN~67890^LAB~EXTERNAL456^EXTERNAL

This field repeats three times, each with an identifier and an identifier type.

Escape character (``): Allows you to include a delimiter character inside a field value without breaking the message structure. For example, to include the text Hello|World inside a field:

HelloFWorld

The F represents a literal |. The escape codes are:

  • F → field separator (|)
  • S → component separator (^)
  • T → sub-component separator (&)
  • E → escape character (``)
  • R → repetition separator (~)

Sub-component separator (&): Divides sub-components within a component. Used only in data types that have sub-components, like CX (composite ID with check digit):

12345&MRN&facility&2

Here, the first sub-component is the ID value, the second is the check digit, the third is the assigning authority namespace, and the fourth is the assigning authority universal ID type.

MSH Header — Field-by-Field

The MSH (Message Header) segment is always the first segment in an HL7 message. It defines the message metadata, delimiters, and encoding characters for the entire message. Every other segment follows the format: SEGMENT_ID|field1|field2|..., but MSH is special because its first field is the field separator itself.

MSH segment format:

MSH|^~&|sending_app|sending_facility|receiving_app|receiving_facility|timestamp|security|message_type|message_control_id|processing_id|version_id|sequence_number|continuation_pointer|accept_ack_type|app_ack_type|country_code|character_set|principal_language_of_message

Key MSH fields:

FieldNameTypeDescription
MSH-0Segment IDAlways "MSH" (not counted in the field sequence)
MSH-1Field SeparatorSTThe character separating fields (usually `
MSH-2Encoding CharactersSTThe component, repetition, escape, and sub-component separators (^~&)
MSH-3Sending ApplicationHDApplication or system sending the message
MSH-4Sending FacilityHDFacility or organization sending the message
MSH-5Receiving ApplicationHDApplication or system receiving the message
MSH-6Receiving FacilityHDFacility or organization receiving the message
MSH-7TimestampTSDate and time the message was created
MSH-8SecuritySTSecurity information (often empty)
MSH-9Message TypeMSGType and trigger event (e.g., ADT^A01)
MSH-10Message Control IDSTUnique identifier for this message
MSH-11Processing IDPTTest, Training, or Production (T, T, or P)
MSH-12Version IDVIDHL7 version (e.g., 2.5.1)
MSH-13Sequence NumberNMMessage sequence number (for batches)
MSH-14Continuation PointerSTContinuation token for multi-part messages
MSH-15Accept Acknowledgment TypeIDWhether to request an ACK (AL, NE, SU, ER)
MSH-16Application Acknowledgment TypeIDWhether to request an application ACK (AL, NE, SU, ER)
MSH-17Country CodeIDCountry of origin (ISO 3166-1 numeric)
MSH-18Character SetIDCharacter set in use (usually ASCII or UTF-8)
MSH-19Principal Language of MessageCWELanguage of the clinical content

Encoding Characters

The MSH-2 field (encoding characters) defines the delimiter set used in the entire message. The standard value is ^~&, representing:

  • ^ — component separator
  • ~ — repetition separator
  • `` — escape character
  • & — sub-component separator

This field appears immediately after MSH-1 (the field separator) with no field separator between them. An HL7 message always begins:

MSH|^~&|...

The escape character is crucial because it allows you to include the delimiter characters themselves in field values. When parsing an HL7 message:

  1. Read the first character after "MSH" to identify the field separator (usually |)
  2. Read the next four characters to identify the encoding characters
  3. Use these delimiters to parse the rest of the message

This self-identifying approach makes HL7 v2 robust: a parser can be configured dynamically based on what it reads, rather than requiring pre-configuration.

Annotated Sample Message

Here is a minimal but complete HL7 message with annotations showing the segment, field, component, and delimiter structure:

MSH|^~&|EHR|HOSPITAL|LAB|LABFACILITY|20260701120000||ADT^A01^ADT_A01|MSG001|P|2.5.1
PID||12345^MRN~67890^LAB|12345^^^NPI||DOE^JOHN^M^DR^|||19800515|M|||123 Main St^^Springfield^IL^62701^USA||555-1234|(555)555-5678||ENG|S|||PATIENT001|||||USA|
PV1||I|CARDIO^BED401||H|||123456^Smith^Mary^Dr^MD^|||||||||C||||||||20260701100000||||||||||||||||||||||||||||||||

Segment-by-segment breakdown:

MSH (Message Header):

MSH|^~&|EHR|HOSPITAL|LAB|LABFACILITY|20260701120000||ADT^A01^ADT_A01|MSG001|P|2.5.1
   |
   +-- MSH-1 (Field Separator): |
   |
   +-- MSH-2 (Encoding Characters): ^~&
       |
       +-- Component separator: ^
       +-- Repetition separator: ~
       +-- Escape character: 
       +-- Sub-component separator: &
   |
   +-- MSH-3 (Sending App): EHR
   +-- MSH-4 (Sending Facility): HOSPITAL
   +-- MSH-5 (Receiving App): LAB
   +-- MSH-6 (Receiving Facility): LABFACILITY
   +-- MSH-7 (Timestamp): 20260701120000
   +-- MSH-8 (Security): [empty]
   +-- MSH-9 (Message Type): ADT^A01^ADT_A01
       |
       +-- Component 1 (Message Code): ADT
       +-- Component 2 (Trigger Event): A01
       +-- Component 3 (Message Structure): ADT_A01
   +-- MSH-10 (Message Control ID): MSG001
   +-- MSH-11 (Processing ID): P
   +-- MSH-12 (Version): 2.5.1

PID (Patient Identification):

PID||12345^MRN~67890^LAB|12345^^^NPI||DOE^JOHN^M^DR^|||19800515|M|||123 Main St^^Springfield^IL^62701^USA||555-1234|(555)555-5678||ENG|S|||PATIENT001|||||USA|
   |  |                     |          |  |                          |           |
   |  |                     |          |  |                          |           +-- Multiple empty fields (components/subcomponents)
   |  |                     |          |  |                          +-- PID-13 (Home Phone): 555-1234
   |  |                     |          |  +-- PID-11 (Address): 123 Main St^^Springfield^IL^62701^USA
   |  |                     |          |     (Component breakdown: street^apt^city^state^zip^country)
   |  |                     |          +-- PID-8 (Administrative Sex): M
   |  |                     +-- PID-7 (Date of Birth): 19800515
   |  |                     |
   |  |                     +-- PID-5 (Patient Name): DOE^JOHN^M^DR^
   |  |                         (Component breakdown: family^given^middle^prefix^suffix)
   |  |
   |  +-- PID-3 (Patient Identifier List): 12345^MRN~67890^LAB~12345^^^NPI
   |      (Repetition breakdown:
   |       - 12345^MRN (ID 12345, type MRN)
   |       - ~ (repetition separator)
   |       - 67890^LAB (ID 67890, type LAB)
   |       - ~ (repetition separator)
   |       - 12345^^^NPI (ID 12345, empty check digit, empty assigning authority, type NPI))
   |
   +-- PID-1 (Set ID): [empty]
   +-- PID-2: [empty]
   ...

PV1 (Patient Visit):

PV1||I|CARDIO^BED401||H|||123456^Smith^Mary^Dr^MD^|||||||||C||||||||20260701100000|...
   |  | |            | | |  |                        |
   |  | |            | | |  |                        +-- PV1-8 (Attending Doctor): 123456^Smith^Mary^Dr^MD^
   |  | |            | | |  +-- PV1-7: [empty]
   |  | |            | | +-- PV1-6 (Prior Temporary Location): H
   |  | |            | +-- PV1-5: [empty]
   |  | |            +-- PV1-4 (Admission Type): [empty]
   |  | |                (Note: address string with component separators)
   |  | +-- PV1-3 (Assigned Patient Location): CARDIO^BED401
   |  |     (Component breakdown: unit^bed)
   |  +-- PV1-2 (Patient Class): I (Inpatient)
   |
   +-- PV1-1 (Set ID): [empty]
   ...
   +-- PV1-19 (Visit Number): 20260701100000

Common Parsing Pitfalls

1. Forgetting the MSH Special Case

MSH is the only segment where the field separator immediately follows the segment ID without a field separator character between them. A parser that treats MSH like any other segment (expecting MSH| then reading the first field as empty) will misalign all subsequent fields. Always handle MSH specially: read the first field separator, then read the encoding characters, then use those to parse the rest.

2. Mishandling the Escape Character

The escape character (``) appears in field values, not just between fields. For example, the text Hello|World is encoded as HelloFWorld. A naive parser that splits on | without respect to escape sequences will break on the escaped pipe. Always process escape sequences during field parsing, not before tokenizing the message.

3. Ignoring Trailing Empty Components

In XPN (person name), trailing empty components are often included. For example:

DOE^JOHN^^DR^

Here, the empty third component represents an empty middle name, and the fourth component is the prefix. A parser that ignores trailing delimiters will lose the position of the suffix component. Preserve the component count.

4. Confusing Repetitions with Components

A field can repeat (separated by ~) and also have components (separated by ^). For example:

12345^MRN~67890^LAB

This is a repeating field with two occurrences, each with two components. A parser must first split by ~ to get repetitions, then split each repetition by ^ to get components. Reversing the order will produce incorrect results.

5. Not Respecting Optional Fields

Many fields are optional. An HL7 message may have consecutive field separators (e.g., ||) representing empty fields. A parser must distinguish between "field is present but empty" and "field is absent" by respecting the delimiter count, not by collapsing consecutive delimiters.

6. Assuming a Fixed Number of Fields

The HL7 standard defines a maximum field count per segment, but senders may include additional (often local) fields beyond the standard. A parser should gracefully ignore extra fields rather than failing. Conversely, a receiver should not assume that a segment is complete if a particular field is expected; always validate by checking field position, not by assuming a segment has a fixed number of fields.

7. Mishandling Sub-components

Sub-components are rare but important. The CX data type (composite ID) includes the assigning authority, which has sub-components for namespace ID, universal ID, and universal ID type. A field like:

12345&MRN&facility&2

requires splitting by & to extract the sub-components. A parser that only splits by ^ and ~ will treat the entire field as a single value.

Sources

← Back to HL7 v2 Guide

Ready to Integrate This Into Your Workflow?

Talk to a Vorro expert about implementing HL7 v2 in your specific environment.

Browse HL7 v2 Guides
HL7 Message Structure: Segments, Fields, Components, and Delimiters | Vorro Academy | Vorro