Healthcare Integration-11 min read

Mirth Connect channel architecture: source, filter, transformer, destination

How to structure NextGen Connect (formerly Mirth Connect) channels — source, filter, transformer, destination, configuration maps, error queues versus retry, and Git export of channel XML.

Ala Ben Aicha

Mirth Connect channel architecture: source, filter, transformer, destination

Direct answer

A NextGen Connect (Mirth Connect) channel is source, filter, transformer, destination. Put environment URLs in the configuration map, not the channel XML. Error queues are not retries. Export channels to Git.

Channel mapping

Mirth Connect is the product name most interface engineers still search. The vendor name is NextGen Connect (Mirth Connect by NextGen Healthcare). On 19 March 2025, with version 4.6, NextGen moved new releases to a commercial licence; source for 4.6+ is not on GitHub. Older source, upgrade notes and the FAQ remain. This page is channel architecture, not a licence opinion.

A channel is one pipeline:

Source connector
    → source filter (accept / drop)
    → source transformer (normalize)
    → destination 1..n
         → destination filter
         → destination transformer
         → send + response
    → postprocessor
Stage What it does What it must not do
Source Receive or poll: TCP/MLLP listener, HTTP, file, database, JMS, channel reader Encode the whole mapping; that belongs in transformers
Source filter Boolean: process this message at all (MSH-9, sending facility, basic structure) Mutate msg; filters that change data hide failures
Source transformer Normalize: namespaces, dates, identifier systems, FHIR JSON Call production HTTP without a destination queue in front
Destination filter Route subsets (A01 to registration, A08 to demographics, ORU to the lab channel) Duplicate the source filter without a reason
Destination transformer Build the outbound payload for that system Hard-code hostnames, ports, or secrets
Destination Deliver (MLLP, HTTP FHIR, file, channel writer) Be the only copy of environment configuration

Maps (from the NextGen variable-map list):

Map JS / shortcut Lifetime
Connector connectorMap / $co This connector, this message
Channel channelMap / $c This channel, this message
Source sourceMap / $s From the source connector
Global channel globalChannelMap / $gc This channel, process lifetime
Global globalMap / $g Server process
Configuration configurationMap / $cfg File on disk (configuration.properties under appdata), not the in-memory global map

The configuration map is the environment file: FHIR bases, MLLP hosts, path prefixes. NextGen stores it as a flat file and does not include it in server configuration exports, so the same channel XML can move across test and production. That is the point.

Hybrid v2 plus FHIR still sits on this pipeline — the v2-to-FHIR migration playbook. Order/result identifiers belong in radiology and lab workflows, not in a second copy of those maps inside every transformer.

Identifier traps

Trap Symptom Fix
Hostnames in transformer JavaScript Channel XML differs per environment; Git diffs are noise $cfg('fhir.base') / $cfg('his.mllp.host') in connector properties
Config map keys colliding with globalChannelMap Wrong URL because lookup precedence hits $gc first Do not reuse config-map names in other maps
Source filter too tight A08 never updates FHIR Patient Filter on message family (ADT) at source; split A01/A08 at destination
One channel for ADT + ORM + ORU Shared transformer with a forest of if (msg['MSH']…) One channel per inbound contract, or a thin source that channel-writes to specialists
Treating ERROR status as “will retry” Silent loss after max retries See queues below
Exporting channels without code templates Import misses shared functions Export libraries with the channel, or version templates in the same Git repo

HL7 field indexing in Rhino is 1-based (msg['PID']['PID.3']['PID.3.1']). Empty fields throw if you call .toString() without a guard — that is a transformer bug, not a “bad ADT”.

Test fixtures

De-identified. Channel XML is huge; keep fixtures as messages + expected outbound, not as screenshots of the administrator.

Inbound ADT (same Jane Example as the ADT article):

MSH|^~\&|HIS|HOSP-A|MIRTH|HOSP-A|20260917103000||ADT^A01^ADT_A01|MSG0001|P|2.5
PID|1||HOSP-MRN-0001^^^HOSP-A^MR||EXAMPLE^JANE^Q||19770412|F
PV1|1|I|||||||||||||||||VN-2026-00042^^^HOSP-A^VN|||||||||||||||||||||||||20260917103000

Configuration map (never commit real secrets; this is a shape):

his.mllp.host=his-test.example.org
his.mllp.port=2575
fhir.base=https://fhir-test.example.org/fhir
fhir.patient.mrn.system=https://hosp-a.example.org/mrn

Destination HTTP body (truncated Patient):

{
  "resourceType": "Patient",
  "identifier": [
    {
      "system": "https://hosp-a.example.org/mrn",
      "value": "HOSP-MRN-0001"
    }
  ],
  "name": [{ "family": "EXAMPLE", "given": ["JANE", "Q"] }],
  "birthDate": "1977-04-12"
}

Minimum tests:

  1. Source filter: ADT^A01 accepted; ORM dropped (or routed elsewhere).
  2. Transformer guard: PID-3 empty → filtered or ERROR with a reason, not a TypeError.
  3. Config map: same channel XML against test and production bases.
  4. Destination queue: stop the FHIR server, send A01, message QUEUED, server returns, message SENT once.
  5. Git: export channel XML, change one transformer line, diff shows that line — not a 4,000-line property reorder.

Never paste live PHI into channel descriptions, test messages stored in Git, or the administrator’s “Generate” pane on a production box.

Failure modes and rollback

Destination queues are not the error table.

Mode Behaviour Use
Never Failed send fails the destination immediately Only if a later destination must see a synchronous response
On failure Try once, then queue Default for FHIR HTTP and MLLP toward brittle receivers
Always Queue first, send async; downstream sees QUEUED High volume; accept out-of-order if you also enable rotate

ERROR means the message is not going to retry by itself. Operators reprocess, or you route failures to an error channel (channel writer) that pages a human. Retry is the destination queue. Mixing the two is how ADT A03 sits behind a poison A08 until census is fiction.

Git export: channels live as XML in the engine database. There is no native “the repo is the runtime”. Practical pattern: REST export each channel to one file ({id}-{name}.xml), pretty-print for diffs, pull request, import + deploy on the target. Do not store configuration.properties in the same repo as production secrets; store keys and inject values per environment.

Failure Detection Rollback
Transformer exception Connector ERROR, MLLP still ACKed if you ACK’d at source too early ACK after destination success, or ACK at source and accept that you now own replay
Queue backup QUEUED count climbing Pause source; fix receiver; do not halt-and-wipe the queue
Wrong environment Test Patient on production FHIR Config map + separate client IDs; disable the production destination in lower environments
Loop via channel writer CPU cliff Source map of MSH-3; drop messages this engine just emitted

Disable a bad writer by undeploying that destination (or the channel) without touching the HIS feed. Keep the inbound MLLP up if clinical senders cannot buffer.

Related service

If you need NextGen Connect / Mirth channels designed, exported, and tested (ADT, ORM/ORU, FHIR HTTP), that is Mirth Connect. For a scoped channel-architecture spike, use contact with project intent.

This page is not a NextGen licence, not Channel History as a substitute for Git, and not a throughput benchmark.

Mirth ConnectNextGen ConnectHL7 v2Integration EngineFHIRChannelsConfiguration Map

Related reading and services

Let's Continue the Conversation

Have questions about this topic? I'd love to hear from you.

Get in Touch

🍪 Do you like cookies?

Allow analytics cookies to help understand site visits and enquiries? Optional analytics stays off until you accept.

Learn More