In a hospital information system the point-to-point integrations grow with the square of the connected systems, and every new departmental application forces edits to the ones already in place. An integration engine such as Mirth Connect exists to break that growth: systems stop talking to each other and instead write to, or read from, a central point that listens, validates, transforms, routes and logs.
Context
Mirth Connect started in 2006 at WebReach, later Mirth Corporation, and is now maintained by NextGen Healthcare under the name NextGen Connect Integration Engine โ though the historical Mirth brand is still what everyone uses. The code is public on GitHub (nextgenhealthcare/connect) and, from the 4.0 series released in March 2021, it ships under the Mozilla Public License 2.0 (it was MPL 1.1 before). That same 4.0 series updated the Rhino JavaScript engine, introduced a debugger for channel scripts and aligned support with Java 11.
The engine does one thing: it translates between dialects. Two wards in the same hospital both emit HL7 v2.x, yet one orders its OBX segments its own way, another populates PID-18 where the first uses PID-3, a third expects the ACK with a different timeout. HL7 v2 is a standard on paper, but that does not make the systems actually interoperable, and a mediation layer is still indispensable.
Channel architecture
The unit of work is the channel: a pipeline with one source and one or more destinations.
Source connector โ Source filter โ Source transformer
โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโ
Destination 1 Destination 2 Destination N
(filter+transformer) (filter+transformer) (filter+transformer)
The source connector receives the raw message. In healthcare the most frequent case is the TCP/MLLP (Minimal Lower Layer Protocol) listener, which wraps HL7 v2 messages in a frame of control bytes (0x0B leading, 0x1C 0x0D trailing). The other connectors cover HTTP/HTTPS, directory reads, JDBC polling, JMS, SMTP/IMAP and DICOM C-STORE.
Nearly all the logic lives in the transformer. Mirth converts the inbound message into a navigable object and lets you manipulate it with JavaScript. For HL7 v2 that object is an E4X (ECMAScript for XML) representation, an old language extension that Rhino implements: segments become XML nodes reached with direct notation.
// msg = inbound message (E4X), tmp = outbound message
var surname = msg['PID']['PID.5']['PID.5.1'].toString();
if (msg['MSH']['MSH.9']['MSH.9.1'].toString() === 'ORU') {
tmp['OBR']['OBR.4']['OBR.4.2'] = mapCode(surname);
}
E4X was deprecated in mainstream JavaScript environments years ago and belongs to no ratified edition of ECMAScript; it survives in Mirth because Rhino implements it and because navigating HL7 v2 segments this way gives a concrete syntactic advantage. Worth keeping in mind: transformer code is not portable JavaScript.
The destinations reproduce the same connector repertoire on the way out, each with its own filter and transformer. A single pipeline can therefore fan out: it receives a laboratory ORU^R01 and writes it at the same time to the patient record over MLLP, to a data warehouse over JDBC and to a REST client.
Formats handled
Mirth handles several clinical formats natively, with dedicated parsers:
- HL7 v2.x โ segment access via E4X, validation against profiles, automatic
ACKgeneration. - HL7 CDA R2 / HL7 v3 โ XML navigable with XPath, used for documents bound for the shared health record.
- FHIR R4 (the HL7 normative standard published in 2019) โ JSON/XML payloads; the engine exposes Java APIs to build REST clients and handle
Bundleresources. - X12, DICOM, XML/JSON/Delimited โ administrative, imaging and generic formats.
This breadth gradually shifts the engineโs use from pure routing toward conversion between standards: taking HL7 v2 from a legacy HIS and producing FHIR Observation or DiagnosticReport resources for a more recent data platform.
The critical point
The channel model is clean as long as the transformer stays a pure function over the message. It gives way when bent to what it was not designed for: synchronous calls to external systems inside the transformer. A FHIR Observation that, to be built, has to make an HTTP lookup against a terminology server ties the channelโs throughput to that serverโs latency. Under a laboratory spike โ thousands of ORU messages in minutes โ the source connectorโs thread pool saturates waiting on I/O, the queue swells, and the symptom shows up far from its cause.
The second fragile point is the nature of the artefacts. Channel configurations are data โ serialised XML with JavaScript nested in the nodes โ not source files in a project tree. You can export them, version them in Git and put them under review, but nothing in the tool requires it: the path of least resistance is to edit the channel in the Administrator and click Deploy. From there come the most common operational drifts: logic that exists only in production, no change history beyond the audit log, transformers nobody can redeploy from scratch any more.
Operational consequences
Treating configurations as code โ export, repository, code review, deployment from a pipeline via the mirthcli CLI โ separates a governable engine from a blind spot. The message store, through which messages flow and where they persist, must be sized with the Message Pruner enabled per channel: an instance processing millions of messages a day with no retention policy fills the database and degrades the Message Browser queries, which are the very tool you reach for when a flow breaks.
For spikes, mediation toward slow external systems must be moved outside the synchronous transformer: a dedicated destination with a queue and retry absorbs latency variability without blocking ingestion upstream.
Limits
Active-active clustering is not part of the open source distribution: it exists only in the commercial extension, and high availability on the MPL-licensed code has to be built by hand, with external failover and a shared database. Relying on Rhino and E4X means the skill required is not general JavaScript but a dated dialect of it, with a narrow pool of developers. And an engine remains a point of centralisation: it shrinks the integration graph, but in exchange it concentrates an operational risk that must be tended as such.
The open source alternatives โ Apache Camel with camel-hl7 and camel-fhir, WSO2 Enterprise Integrator, Apache NiFi for dataflows โ offer different models: generally more code and more flexibility, against fewer ready-made vertical tools. The choice depends on how much of the problem is classic HL7 v2 routing and how much is integration with recent systems.
- https://github.com/nextgenhealthcare/connect
- https://github.com/nextgenhealthcare/connect/wiki/4.0.0---Whatโs-New
- https://www.hl7.org/implement/standards/product_brief.cfm?product_id=185 (HL7 v2)
- https://www.hl7.org/fhir/R4/
- https://www.hl7.org/implement/standards/product_brief.cfm?product_id=7 (CDA R2)
- https://www.mozilla.org/en-US/MPL/2.0/
- https://www.noze.it/en/insights/mirth-connect-integration-engine/
Cover image: Diagram of the MSH (Message Header) segment of an HL7 version 2 message, with fields separated by the pipe character โ diagram by Dipl.-Inform. Oliver S. Lazar, public domain โ https://commons.wikimedia.org/wiki/File:HL7_msh.png