Nirmitee.io
Mirth Connect

Mirth Connect HL7 Interface Engine: Production Deployment Guide

March 17, 202616 min readUpdated Oct 19, 2026
Written by
Gulshan Prajapati
Gulshan Prajapati

Software Development Expert

Writes about software development, scalable architecture, and practical problem-solving across modern digital products. Focuses on turning complex technical ideas into clear, real-world solutions.

Mirth Connect HL7 Interface Engine: Production Deployment Guide

New to the terms? Start with what an HL7 interface is, then come back for the engine setup. If you would rather have the interfaces built and supported for you, see our HL7 integration services.

Deploying Mirth Connect in production is not the same as getting it running in dev. This guide walks through the full production setup — from channel architecture and clustering to monitoring alerts and DR failover — so your HL7 interfaces stay up when your hospital needs them. This is a greenfield deployment guide for teams starting fresh.

This guide covers everything you need to deploy Mirth Connect in production: installation, channel architecture, JavaScript transformers, high availability with PostgreSQL, Docker deployment, monitoring with Prometheus, and security hardening. These are not sandbox configurations — they are the patterns we use at Nirmitee for production healthcare integrations.

Watch: What an Interface Engine Does (and Why Hospitals Need One) | Mirth Connect for Business Leaders (2:21).

Installation and Initial Configuration

System Requirements

ComponentMinimum (Dev)Recommended (Production)High Volume (50K+ msgs/day)
CPU2 cores8 cores16+ cores
RAM4 GB16 GB32 GB
Disk20 GB SSD100 GB SSD500 GB NVMe
JDKOpenJDK 17OpenJDK 17 (Temurin)OpenJDK 17 (Temurin)
DatabaseDerby (embedded)PostgreSQL 15+PostgreSQL 16 with replication
OSAny (Java)RHEL 8+ or Ubuntu 22.04RHEL 8+ or Ubuntu 22.04

Installation Steps

# 1. Download Mirth Connect (version 4.5.x as of 2026)
wget https://github.com/nextgenhealthcare/connect/releases/download/4.5.0/mirthconnect-4.5.0-unix.tar.gz
tar xzf mirthconnect-4.5.0-unix.tar.gz
cd Mirth\ Connect/

# 2. Configure PostgreSQL database
sudo -u postgres psql << SQL
CREATE USER mirth WITH PASSWORD 'your-secure-password';
CREATE DATABASE mirthdb OWNER mirth;
GRANT ALL PRIVILEGES ON DATABASE mirthdb TO mirth;
SQL

# 3. Update mirth.properties for PostgreSQL
cat > conf/mirth.properties << EOF
database = postgres
database.url = jdbc:postgresql://localhost:5432/mirthdb
database.username = mirth
database.password = your-secure-password
database.max-connections = 50

# Admin console HTTPS
https.port = 8443
https.client.protocols = TLSv1.2,TLSv1.3

# JVM tuning
jvm.heap.size = 8g
jvm.args = -XX:+UseG1GC -XX:MaxGCPauseMillis=100
EOF

# 4. Start Mirth Connect
./mcservice start

# 5. Verify it is running
curl -sk https://localhost:8443/api/server/version
# Should return: "4.5.0"

Channel Architecture: Patterns That Scale

Still choosing an engine? See our healthcare interface engine comparison before you commit to Mirth.

A well-designed channel architecture separates concerns and enables independent scaling and monitoring.

Pattern 1: Protocol-Specific Inbound Channels

Create one inbound channel per protocol and source system combination. This isolates failures — if the lab system sends malformed messages, only the lab inbound channel is affected.

  • ADT-Inbound-Epic — TCP listener on port 6661, receives ADT^A01/A02/A03/A04/A08 from Epic
  • Lab-Inbound-Sunquest — TCP listener on port 6662, receives ORU^R01 from Sunquest LIS
  • Pharmacy-Inbound-Pyxis — TCP listener on port 6663, receives RDE^O11 from BD Pyxis
  • FHIR-Inbound-API — HTTP listener on port 8080, receives FHIR R4 Bundles from modern applications

Pattern 2: Transformation Channels

Separate transformation logic from I/O. Inbound channels pass raw messages to transformation channels via the Channel Writer destination. This allows you to reuse transformers across multiple sources.

Pattern 3: Outbound Channels with Retry Logic

Outbound channels deliver transformed messages to destination systems. Each destination gets its own channel with appropriate retry and error handling.

JavaScript Transformers: Real Production Examples

Mirth's JavaScript transformer is where the integration logic lives. Here are production-tested transformer patterns.

ADT Message Parser and Router

// Source Transformer: Parse ADT and enrich with routing metadata
// Channel: ADT-Transform

// Extract key fields from the HL7v2 message
var msgType = msg['MSH']['MSH.9']['MSH.9.1'].toString();
var triggerEvent = msg['MSH']['MSH.9']['MSH.9.2'].toString();
var patientId = '';
var patientName = '';

// Defensive null checks (production messages have missing segments)
if (msg['PID'] && msg['PID']['PID.3'] && msg['PID']['PID.3']['PID.3.1']) {
    patientId = msg['PID']['PID.3']['PID.3.1'].toString();
}
if (msg['PID'] && msg['PID']['PID.5']) {
    var lastName = msg['PID']['PID.5']['PID.5.1'] ? msg['PID']['PID.5']['PID.5.1'].toString() : '';
    var firstName = msg['PID']['PID.5']['PID.5.2'] ? msg['PID']['PID.5']['PID.5.2'].toString() : '';
    patientName = lastName + ', ' + firstName;
}

// Set channel map variables for routing
channelMap.put('messageType', msgType + '^' + triggerEvent);
channelMap.put('patientId', patientId);
channelMap.put('patientName', patientName);

// Determine destination based on message type
var destinations = [];
switch (triggerEvent) {
    case 'A01': // Admission
        destinations = ['ADT-Out-Billing', 'ADT-Out-Pharmacy', 'ADT-Out-Analytics'];
        break;
    case 'A03': // Discharge
        destinations = ['ADT-Out-Billing', 'ADT-Out-Quality', 'ADT-Out-Analytics'];
        break;
    case 'A08': // Update
        destinations = ['ADT-Out-Demographics'];
        break;
    default:
        destinations = ['ADT-Out-Archive'];
}
channelMap.put('destinations', destinations.join(','));

logger.info('ADT ' + triggerEvent + ' for patient ' + patientId);

HL7v2 to FHIR Transformer

// Transformer: HL7v2 ORU^R01 -> FHIR DiagnosticReport + Observations
// Channel: Lab-FHIR-Transform

var patientRef = 'Patient/' + msg['PID']['PID.3']['PID.3.1'].toString();
var observations = [];

// Iterate over OBX segments (lab results)
for (var i = 0; i < msg['OBX'].length(); i++) {
    var obx = msg['OBX'][i];
    var observation = {
        "resourceType": "Observation",
        "status": mapObservationStatus(obx['OBX.11'].toString()),
        "code": {
            "coding": [{
                "system": "http://loinc.org",
                "code": obx['OBX.3']['OBX.3.1'].toString(),
                "display": obx['OBX.3']['OBX.3.2'].toString()
            }]
        },
        "subject": { "reference": patientRef },
        "valueQuantity": {
            "value": parseFloat(obx['OBX.5'].toString()),
            "unit": obx['OBX.6']['OBX.6.1'] ? obx['OBX.6']['OBX.6.1'].toString() : '',
            "system": "http://unitsofmeasure.org"
        },
        "referenceRange": [{
            "text": obx['OBX.7'] ? obx['OBX.7'].toString() : ''
        }],
        "interpretation": obx['OBX.8'] ? [{
            "coding": [{
                "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
                "code": mapInterpretation(obx['OBX.8'].toString())
            }]
        }] : undefined
    };
    observations.push(observation);
}

function mapObservationStatus(hl7Status) {
    var statusMap = {'F': 'final', 'P': 'preliminary', 'C': 'corrected', 'X': 'cancelled'};
    return statusMap[hl7Status] || 'unknown';
}

function mapInterpretation(hl7Interp) {
    var interpMap = {'H': 'H', 'L': 'L', 'HH': 'HH', 'LL': 'LL', 'N': 'N', 'A': 'A'};
    return interpMap[hl7Interp] || hl7Interp;
}

// Build FHIR Bundle
var bundle = {
    "resourceType": "Bundle",
    "type": "transaction",
    "entry": observations.map(function(obs) {
        return {
            "resource": obs,
            "request": { "method": "POST", "url": "Observation" }
        };
    })
};

channelMap.put('fhirBundle', JSON.stringify(bundle));

High Availability with PostgreSQL

Production healthcare integrations require high availability. Here is the HA architecture we deploy:

  • Two Mirth Connect nodes behind an L4 load balancer (HAProxy or AWS NLB). Both nodes are active, processing different channels or sharing load for high-volume channels.
     
  • PostgreSQL primary + synchronous replica. Both Mirth nodes write to the primary. The replica provides automatic failover through Patroni or pg_auto_failover.
     
  • Shared configuration through the PostgreSQL database. Channel configurations, code templates, and global scripts are stored in the database and shared across nodes.
     
  • Health checks on each node. The load balancer checks Mirth's API health endpoint. If a node fails health checks, traffic routes to the surviving node.

HAProxy Configuration

# haproxy.cfg for Mirth Connect HL7 TCP
frontend hl7_adt
    bind *:6661
    mode tcp
    default_backend mirth_adt

backend mirth_adt
    mode tcp
    balance roundrobin
    option tcp-check
    server mirth1 10.0.1.10:6661 check inter 5s fall 3 rise 2
    server mirth2 10.0.1.11:6661 check inter 5s fall 3 rise 2

frontend hl7_lab
    bind *:6662
    mode tcp
    default_backend mirth_lab

backend mirth_lab
    mode tcp
    balance roundrobin
    server mirth1 10.0.1.10:6662 check inter 5s fall 3 rise 2
    server mirth2 10.0.1.11:6662 check inter 5s fall 3 rise 2

Docker Deployment

# docker-compose.yml - Production Mirth Connect
version: "3.8"
services:
  mirth:
    image: nextgenhealthcare/connect:4.5.0
    ports:
      - "8443:8443"
      - "6661:6661"
      - "6662:6662"
      - "6663:6663"
    volumes:
      - ./mirth-config:/opt/connect/appdata
      - ./custom-lib:/opt/connect/custom-lib
      - ./ssl:/opt/connect/ssl
    environment:
      - DATABASE=postgres
      - DATABASE_URL=jdbc:postgresql://postgres:5432/mirthdb
      - DATABASE_USERNAME=mirth
      - DATABASE_PASSWORD_FILE=/run/secrets/db_password
      - VMOPTIONS=-Xmx8g -XX:+UseG1GC
    secrets:
      - db_password
    healthcheck:
      test: ["CMD", "curl", "-skf", "https://localhost:8443/api/server/version"]
      interval: 30s
      timeout: 10s
      retries: 3
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

  postgres:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=mirthdb
      - POSTGRES_USER=mirth
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
    secrets:
      - db_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mirth -d mirthdb"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

secrets:
  db_password:
    file: ./secrets/db_password.txt

volumes:
  pgdata:

Security Hardening for HIPAA

Healthcare integration engines handle PHI and must meet HIPAA Technical Safeguards. Here is the security hardening checklist:

Network Security

  • TLS 1.2+ for all connections — Configure Mirth to use TLS for both the admin console and all channel listeners/destinations. Disable TLS 1.0 and 1.1.
  • IP allowlisting — Restrict inbound connections to known source system IPs. Use firewall rules at the OS level and Mirth's source filter settings.
  • Network segmentation — Place Mirth servers in a private subnet with no direct internet access. Use a jump box or VPN for administrative access.
  • HL7 port protection — HL7 TCP listeners (MLLP) do not natively support TLS. Use stunnel or HAProxy TLS termination in front of MLLP ports.

Application Security

  • RBAC (Role-Based Access Control) — Create separate user accounts for administrators, channel developers, and monitoring. Never share the admin account.
  • Password policy — Enforce strong passwords (12+ characters, complexity requirements). Rotate service account credentials quarterly.
  • Encrypted credential storage — Store database passwords and API keys in Mirth's encrypted global map or external secrets manager (HashiCorp Vault, AWS Secrets Manager).
  • Audit logging — Enable Mirth's built-in audit log for all configuration changes and message access. Forward audit logs to your SIEM.
  • Message content encryption — For messages at rest in the Mirth database, enable PostgreSQL Transparent Data Encryption (TDE) or full-disk encryption.

Monitoring with Prometheus

See our comprehensive guide on Mirth Connect monitoring in production for full details. The key integration: expose Mirth JMX metrics via a Prometheus exporter and build Grafana dashboards for channel throughput, error rates, queue depth, and JVM health.

Common Production Issues and Solutions

IssueSymptomsRoot CauseSolution
Message queue growingQueue depth > 500, latency increasingThe destination system is slow or downCheck destination connectivity; implement a circuit breaker
Out of memory crashesJVM heap > 90%, GC thrashingLarge messages or too many channelsIncrease heap, enable message attachment mode for large payloads
Database connection exhaustionChannel errors, admin console slowConnection pool too small for channel countIncrease max-connections in mirth.properties; tune PostgreSQL
Character encoding corruptionGarbled patient names, broken accentsMismatch between source and Mirth encodingSet character encoding explicitly on channel source connector
Duplicate messagesSame message processed twiceTCP reconnect replays the last messageImplement an idempotency check using MSH.10 (Message Control ID)
Channel deployment failuresThe channel is stuck in the deploying stateJavaScript syntax error in transformerCheck server log; fix transformer syntax; redeploy

Deploy Production Mirth Connect with Nirmitee

At Nirmitee, we deploy and maintain production Mirth Connect instances for healthcare organizations processing millions of messages monthly. From initial setup through high availability configuration to Kafka integration, our team handles the full lifecycle of healthcare integration infrastructure. For the producer and consumer setup, read our guide to Kafka integration in Mirth.

Related guides

This article is part of our complete guide to Mirth Connect: Mirth Connect for healthcare leaders. Related deep-dives:

Need production-grade Mirth Connect help? See our Mirth Connect integration services.


Already running Mirth Connect in production but drowning in interface backlog? See: Clear an HL7v2 Interface Backlog with Mirth Connect

Ready to scale?

Talk to our healthcare engineering team about building, integrating, and shipping faster.

Frequently Asked Questions

What are the system requirements for running Mirth Connect in production?

A production instance needs a Java 11+ runtime, a dedicated PostgreSQL database (never the embedded Derby database), and sufficient heap — 2–4 GB covers most hospital workloads. Plan separate development, staging, and production environments from day one.

How should HL7 channels be structured for scalability?

Use separate protocol-specific inbound channels, dedicated transformation channels, and outbound channels with retry logic — rather than putting receive, transform, and send logic in one monolithic channel. This separation makes channels independently testable, reusable, and easier to troubleshoot.

How do you achieve high availability for an HL7 interface engine?

Run two Mirth nodes against a clustered PostgreSQL database with a load balancer such as HAProxy in front. The standby node takes over when the primary fails, and the shared database ensures no in-flight configuration or message state is lost.

What security hardening does a HIPAA-compliant Mirth deployment need?

At minimum: TLS on every MLLP and HTTP listener, changed default credentials, network segmentation so the admin interface is never internet-facing, encrypted database connections, and audit logging. PHI must be encrypted both in transit and at rest.

How do you monitor Mirth Connect channels in production?

Export channel statistics (throughput, error counts, queue depth) to Prometheus and visualize them in Grafana, with alerting on queue buildup and error-rate spikes. Silent channel failures are the most common production incident — monitoring must detect a stopped or stalled channel before clinical users do.

How does Nirmitee.io approach healthcare software development?

Nirmitee.io follows a healthcare-first engineering approach — every solution is built with HIPAA compliance, HL7/FHIR interoperability standards, and clinical workflow requirements at the core. We combine domain expertise with modern engineering practices to deliver production-ready systems.
Share