HL7 Message Processing with AWS SQS and Node.js

Healthcare systems generate and exchange a massive amount of data every day, from patient admissions to lab results and discharge summaries. But exchanging this information between different software systems is not straightforward because each system may store and process data differently.

That’s where HL7 message processing and FHIR come into play. In this blog, we’ll walk through the basics of HL7, its segments, what FHIR is, and how we can process HL7 messages using AWS SQS and Node.js.

What is HL7?

HL7 (Health Level Seven) is a set of international standards that define how healthcare information is exchanged between systems. It was created to ensure hospitals, labs, pharmacies, and other healthcare providers can talk to each other, regardless of the software they use.

For example, when a patient is admitted to a hospital, the hospital system can send an ADT (Admit, Discharge, Transfer) HL7 message to notify other systems like billing or lab management.

Effective HL7 message processing ensures that all these updates flow seamlessly between systems without data loss or duplication.

HL7 Segments

HL7 messages are structured text files. They are made up of segments, which are lines of data separated by carriage returns. Each segment begins with a three-letter code and contains fields separated by a pipe symbol (|).

Here are some common segments:

  • MSH (Message Header): Contains metadata like sender, receiver, and message type.
  • PID (Patient Identification): Holds patient details such as ID, name, date of birth, and gender.
  • OBX (Observation Result): Stores clinical observations or lab results.
  • PV1 (Patient Visit): Includes visit-specific information like admission type, location, and attending doctor.

Example HL7 snippet:

MSH|^~\&|HOSPITAL|123|LAB|456|202509201200||ADT^A01|MSG0001|P|2.5  

PID|1||12345^^^HOSP^MR||DOE^JOHN||19800101|M  

PV1|1|I|2000^2012^01||||1234^SMITH^ADAM

These structures are the foundation of HL7 message processing workflows in healthcare integrations.

What is FHIR?

FHIR (Fast Healthcare Interoperability Resources) is a modern standard developed by HL7. While HL7 v2 messages are plain text and can be complex to parse, FHIR uses JSON or XML formats, making it easier to work with in modern applications.

For instance, the same patient admission message above could be represented as a structured FHIR Patient and Encounter resource in JSON, making it simpler for developers to consume and validate.

In many modern architectures, HL7 message processing pipelines convert HL7 v2 to FHIR formats to ensure interoperability across new systems.

Why AWS SQS for HL7 Processing?

In a hospital ecosystem, thousands of HL7 messages may be generated per hour. If systems directly talk to each other, they can get overloaded.

AWS SQS (Simple Queue Service) acts as a middle layer to handle this load. It works like a message buffer:

  • One system publishes HL7 messages to an SQS queue.
  • Another service (like a Node.js app) reads messages from the queue.
  • The Node.js service processes the message, for example, converting HL7 into FHIR.

This architecture ensures reliable HL7 message processing at scale, keeping systems decoupled and fault-tolerant.

Processing HL7 with Node.js and SQS

Let’s see how we can wire this up.

Step 1: Install Dependencies

npm install @aws-sdk/client-sqs @medplum/fhirtypes uuid

Step 2: Configure SQS Client

import { Consumer } from "sqs-consumer";

import { SQSClient } from "@aws-sdk/client-sqs";

import dotenv from "dotenv";

import { extractPatient } from "../hl7Converter/extractPatient";

import { Patient } from "@medplum/fhirtypes";

dotenv.config();

// Create the SQS client

const sqsClient = new SQSClient({

 region: process.env.AWS_REGION,

 credentials: {

   accessKeyId: process.env.AWS_ACCESS_KEY_ID!,

   secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,

 },

});

// Setup queue URLs

const mainQueueUrl = process.env.QUEUE_URL!;

// Main message processor

async function processHL7Message(message: any) {

 const body = message.Body;

 console.log("Received message:", body);

 const patient: Patient = extractPatient(body);

 console.log("Extracted Patient:", JSON.stringify(patient, null, 2));

}

// Create the SQS consumer

export const app = Consumer.create({

 queueUrl: mainQueueUrl,

 handleMessage: async (message) => {

   await processHL7Message(message);

 },

 sqs: sqsClient,

 batchSize: 10,

 pollingWaitTimeMs: 10000, // Long polling

});

Need Help Setting Up HL7 Message Processing or FHIR Pipelines?

Step 3: Write Utility Function

This function extracts patient data from an HL7 message and converts it into a FHIR R4 Patient resource a key part of automated hl7 message processing pipelines.

import { Patient } from "@medplum/fhirtypes";

import { v4 as uuidv4 } from "uuid";

const patientId = `pat-${uuidv4()}`;

// --- Utilities ---

function formatHL7Date(hl7Date: string): string | undefined {

 if (!hl7Date || hl7Date.length < 8) return undefined;

 return `${hl7Date.slice(0, 4)}-${hl7Date.slice(4, 6)}-${hl7Date.slice(6, 8)}`;

}

export const extractPatient = (hl7: string) => {

 const segments = hl7.trim().split(/\r?\n/);

 const pid = segments.find((s) => s.startsWith("PID|"))?.split("|");

 const patient: Patient = {

   resourceType: "Patient",

   id: patientId,

   text: {

     status: "generated",

     div: `<div xmlns="http://www.w3.org/1999/xhtml">Patient Record</div>`,

   },

   identifier: pid?.[3]

     ? [{ system: "http://hospital.org/mrn", value: pid[3].split("^")[0] }]

     : undefined,

   name: pid?.[5]

     ? [{ family: pid[5].split("^")[0], given: [pid[5].split("^")[1] || ""] }]

     : undefined,

   gender: pid?.[8] === "M" ? "male" : pid?.[8] === "F" ? "female" : "unknown",

   birthDate: pid?.[7] ? formatHL7Date(pid[7]) : undefined,

   telecom: pid?.[13] ? [{ system: "phone", value: pid[13] }] : undefined,

   address: pid?.[11]

     ? [

         {

           line: [pid[11].split("^")[0] || ""],

           city: pid[11].split("^")[2] || "",

           state: pid[11].split("^")[3] || "",

           postalCode: pid[11].split("^")[4] || "",

           country: pid[11].split("^")[5] || "",

         },

       ]

     : undefined,

 };




 return patient;

};

Step 4: Start SQS Listener

import { app as sqsListener } from "./common/utils/sqsListener";

sqsListener.start();

Step 5: Push Message to Your Queue

Sample HL7 message:

MSH|^~\&|REG_SYS|HOSPITAL|EHR_SYS|HOSPITAL|20250728T093000||ADT^A04|MSG0004|P|2.4

EVN|A04|20250728T093000

PID|1||123456^^^HOSP^MR||DOE^JOHN^A||19850615|M|||123 MAIN ST^^MUMBAI^MH^400001^IN||+91-9876543210

PV1|1|O|OPD^201^1^HOSP^^ROOM12||||5678^SHARMA^PRIYA^S|||OPD|||||||V123456^HOSP^ADM|||||||||||||||||||||||||20250728

Your SQS listener should be able to poll this message, process it, and output the structured FHIR patient record. This end-to-end flow demonstrates reliable hl7 message processing using AWS SQS and Node.js.

{
"resourceType": "Patient",
"id": "pat-c7db5919-052f-4b8c-9811-27648a9da41e",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">Patient Record</div>"
},
"identifier": [
{
"system": "http://hospital.org/mrn",
"value": "123456"
}
],
"name": [
{
"family": "DOE",
"given": [
"JOHN"
]
}
],
"gender": "male",
"birthDate": "1985-06-15",
"telecom": [
{
"system": "phone",
"value": "+91-9876543210"
}
],
"address": [
{
"line": [
"123 MAIN ST"
],
"city": "MUMBAI",
"state": "MH",
"postalCode": "400001",
"country": "IN"
}
coma

Conclusion

HL7 and FHIR are the backbone of healthcare interoperability. HL7 messages provide a long-established way to exchange data, while FHIR offers a modern, developer-friendly format.
By combining AWS SQS with Node.js, you can create a reliable pipeline to handle hl7 message processing, convert data into FHIR resources, and integrate them with downstream applications.

This architecture not only ensures scalability and fault tolerance but also prepares healthcare systems to adopt FHIR for modern interoperability needs.

Keep Reading

  • Let's create something together!