A Mirth Connect alternative that runs your existing Mirth JavaScript

Perfuse is an open-source healthcare integration engine under Apache 2.0. One static binary, no Java runtime, and 31 MB of memory at rest against Mirth Connect's 383 MB.

Why people look for an alternative

Mirth Connect works, and it has run interfaces at thousands of sites for the better part of twenty years. The reasons teams start looking elsewhere are usually not about whether it functions:

Side by side

PerfuseMirth Connect
Memory at rest31 MB383 MB
Idle CPU0.0%0.13–0.27%
Runtime requiredNone. One static binaryOpenJDK 17
InstallCopy one file254 MB installer plus the JRE
LicenceApache 2.0, no tiersCommercial only since 4.6
Existing Mirth JavaScriptRuns unchanged, including E4XNative
Configuration in the browserEverything, as a rule the project holds itself toMost things
HL7 v2, FHIR, DICOM, X12, CDAAll, in the one binaryHL7 v2 and FHIR core; others via extensions
KafkaSource and destination, keyed for per-patient orderingNo connector
Find a patient across formatsOne box — MRN, name, date of birth, accession — across HL7 v2, FHIR, DICOM and X12Search by metadata, or by hand per format
Production track recordNone yet. v0.1.3Twenty years, thousands of sites

That last row is the one that should decide your evaluation, not the first. Perfuse v0.1.3 has never processed production clinical traffic. The Windows and ARM64 Linux binaries have never been executed at all. Everything that was verified is written down, and so is everything that was not — the record is here. Mirth has two decades of operational history and Perfuse has none. Weigh that honestly.

The part that usually blocks a migration: E4X

Mirth transformers are JavaScript, and a great many of them use E4X — the XML-as-a-language-feature syntax that lets a script write msg['PID']['PID.5']['PID.5.1']. E4X was removed from modern JavaScript engines years ago. Any migration that involves "just move the JavaScript somewhere else" discovers this on the first transformer.

Perfuse runs E4X. That is the single reason a Mirth migration is tractable here rather than a rewrite of every transformer you own.

Migrating a channel

# 1. What would stop you, before you commit to anything
perfuse explain mirth-channel-export.xml

# 2. Convert it
perfuse translate mirth-channel-export.xml -o channels/

# 3. Test it against sample messages
perfuse test channels/labs.yaml

# 4. Run it beside Mirth on real traffic, delivering nothing to anyone
perfuse run channels/labs.yaml

# 5. Prove the two engines agree, on your own messages
perfuse compare -left-name Mirth -right-name Perfuse mirth-out/ perfuse-out/

Step 1 is the one worth running first

perfuse explain reads the export and tells you what converts cleanly, what converts with caveats, and what does not convert at all — by name, not as a count. A migration that surprises you in week three is worse than one that refuses on day one.

What cannot be honoured is refused rather than approximated. Perfuse will decline a destination type it cannot implement properly instead of writing something close and letting you find the difference in production.

Step 4 needs nobody's approval

Add one destination to your existing Mirth channel that forwards a copy to Perfuse, and give the Perfuse channel a directory as its only destination:

name: parallel-run
description: Receives a copy of live traffic from Mirth and files the result. Sends nothing onward.

source:
  type: mllp
  listen: 127.0.0.1:2576

destinations:
  # The only destination is a directory, so this channel cannot reach a
  # downstream system even if it is misconfigured.
  - name: what-perfuse-produced
    type: file
    dir: ./perfuse-out

Nothing is delivered, so no patient is affected and no change-control board needs to meet.

Step 5 is the evidence the decision actually turns on

perfuse compare pairs the two directories by message control id and reports where the engines disagree, grouped by cause — three thousand messages differing for one reason are one finding, not three thousand. A filter disagreement is counted separately from a transformation difference, because one decides whether the receiving system hears about that patient at all and the other changes a value.

Message content is withheld by default, because a report is a thing people paste into tickets. -strict exits non-zero unless the two are identical, which makes it usable in a pipeline.

Questions

Is it a drop-in replacement?

No, and nothing honestly is. It converts your channel exports, runs your JavaScript including E4X, and tells you by name what it cannot carry across. That is as close as an honest answer gets.

What does it cost?

Nothing. Apache 2.0, no commercial tier, no seat count, no feature held back for a paid edition. If you later want support, that is a separate conversation and not a condition of use.

Can I run it alongside Mirth indefinitely?

Yes. A channel whose only destination is a directory delivers to no one, so it can sit beside the incumbent for as long as you want evidence.

What is not there yet?

The honest list is kept in the repository rather than summarised here, because a summary of gaps is the first thing to go stale. Read what was verified and what was not.

Who maintains it?

BioDream LLC. Bug reports are welcome as GitHub issues. Code contributions are not accepted — a single maintainer by design, which is worth knowing before you build on it.

Try it

Download for Linux, macOS or Windows — one file, nothing to install. Or read the reference manual, or the source on GitHub.