Documentation
Install
Every crate, every feature flag, and the command-line tools. Most people need exactly one line of this page.
Requirements
A Rust toolchain, and nothing else. There is no C dependency, no build script that shells out, and no vendored binary anywhere in the workspace.
The minimum supported Rust version is current stable minus two releases,
pinned once in the workspace root and inherited by every member. At the time of
writing that is 1.96. Raising the floor is routine and expected, not a breaking
change to be avoided. See Versions and compatibility for the
policy in full.
As a library
Most users want the umbrella crate. It is a thin re-export — hl7::v2 is the hl7-2 crate and hl7::v3 is hl7-3 — with room left for hl7::fhir. Nothing lives at its root, because a “message”, a “segment”, and a
“code” mean different things in each standard.
# The umbrella crate: hl7::v2 and hl7::v3
cargo add hl7
# With the v2 derive macros
cargo add hl7 --features deriveTake a standard directly if you specifically want it without the indirection:
# HL7 v2 only, no umbrella indirection
cargo add hl7-2
cargo add hl7-2 --features derive
# HL7 v3 only
cargo add hl7-3
cargo add hl7-3 --features deriveOr write the manifest yourself:
Cargo.toml
[dependencies]
hl7 = { version = "0.2", features = ["derive"] }
# Or, taking v2 directly:
hl7-2 = { version = "0.3", features = ["derive"] }Cargo features
Nothing in this workspace is on by default that costs you a dependency, with one exception — hl7-2-mllp's ack feature, which is on because an MLLP receiver that
cannot acknowledge is not much use.
| Crate | Feature | Default | Effect |
|---|---|---|---|
hl7 | derive | off | Forwards to `hl7-2`’s `derive` feature. |
hl7-2 | derive | off | Adds `#[derive(FromHl7)]` and `#[derive(ToHl7)]`; pulls in `hl7-2-derive`. |
hl7-3 | derive | off | Adds `#[derive(FromElement)]`; pulls in `hl7-3-derive`. |
hl7-2-mllp | ack | on | Acknowledgement generation; pulls in `hl7-2`. |
hl7-2-mllp | clock | off | `acknowledge_now`; pulls in `chrono`. Implies `ack`. |
hl7-2-mllp | noncompliance | off | The default framing tolerance becomes lenient. |
The derive macros live in their own crates precisely so that the default build of hl7-2 keeps exactly one dependency: syn and quote are
compiled only for callers who ask for the macros.
MLLP, whose feature set is the most interesting
# Everything: framing, streaming, transport, acknowledgement
cargo add hl7-2-mllp
# Framing, streaming, and transport with no dependencies at all
cargo add hl7-2-mllp --no-default-features
# Add acknowledge_now, which needs a clock
cargo add hl7-2-mllp --features clockAs a command-line tool
Six crates ship a binary. They are useful on their own — the first thing to do with a message from a vendor you have never seen is look at it, and that does not need a Rust project.
# The HL7 v2 tool. The binary is named hl7-v2.
cargo install hl7-2
# The four converters, each its own binary
cargo install hl7-2-from-er7-into-xml
cargo install hl7-2-from-xml-into-er7
cargo install hl7-2-from-er7-into-json
cargo install hl7-2-from-json-into-er7
# The dictionary builder
cargo install hl7-2-from-xsd-into-json-dictionaryNote the name: cargo install hl7-2 installs a binary called hl7-v2. The crate is published as hl7-2 because hl7-v2 on crates.io is an unrelated package; the binary kept the readable name.
Full flag reference: Command line.
Every crate, and its install line
| Crate | Latest | Install | What for |
|---|---|---|---|
hl7 | 0.2.0 | cargo add hl7 | The umbrella crate: one module per HL7 standard |
hl7-2 | 0.3.0 | cargo add hl7-2 | HL7 v2 itself: parse, navigate, validate, modify, render |
hl7-3 | 0.2.0 | cargo add hl7-3 | HL7 v3: the RIM backbone, the data types, the message envelope |
hl7-2-mllp | 0.2.0 | cargo add hl7-2-mllp | MLLP: HL7 v2 framed on a TCP stream |
hl7-2-soap | 0.2.0 | cargo add hl7-2-soap | HL7 v2 carried in a SOAP envelope over HTTP |
hl7-3-soap | 0.2.0 | cargo add hl7-3-soap | HL7 v3 carried in a SOAP envelope over HTTP |
hl7-2-from-er7-into-xml | 0.7.0 | cargo add hl7-2-from-er7-into-xml | ER7 → the official v2.xml XML representation |
hl7-2-from-xml-into-er7 | 0.7.0 | cargo add hl7-2-from-xml-into-er7 | v2.xml XML → ER7 |
hl7-2-from-er7-into-json | 0.5.0 | cargo add hl7-2-from-er7-into-json | ER7 → typed JSON |
hl7-2-from-json-into-er7 | 0.5.0 | cargo add hl7-2-from-json-into-er7 | Typed JSON → ER7 |
hl7-2-derive | 0.2.0 | cargo add hl7-2-derive | #[derive(FromHl7)] and #[derive(ToHl7)] for struct mode |
hl7-3-derive | 0.2.0 | cargo add hl7-3-derive | #[derive(FromElement)] for HL7 v3 struct mode |
hl7-2-from-xsd-into-json-dictionary | 0.2.0 | cargo add hl7-2-from-xsd-into-json-dictionary | HL7 v2.xml XSDs → the JSON dictionary hl7-2 reads |
hl7-2-xml-lite-helper | 0.2.0 | cargo add hl7-2-xml-lite-helper | The small, dependency-free XML reader this family shares |
Versions are the latest published at the time of writing, shown so you can tell roughly how
settled a crate is — not as a constraint to copy. Let cargo add pick.
One crate in the dependency map is not in this workspace: er7, the ER7 encoding layer, which is
its own repository and its own crate. You rarely add it directly — hl7-2 and the
conversion crates re-export what you need.
Building from source
git clone https://github.com/hl7-rust/hl7-rust
cd hl7-rust
cargo build # every workspace member
cargo test # every workspace member's tests
cargo build -p hl7-2 # just one
# Check against the minimum supported Rust version
cargo +1.96 check --workspace --all-targetsOne Cargo.lock at the workspace root covers every member; a crate does not carry
its own. Member crates depend on each other by relative path, exactly as they did when they
were sibling repositories — the flat one-directory-per-crate layout was kept specifically so
those paths did not have to change.
Verifying the install
The smallest thing that proves the library is wired up:
use hl7::v2;
fn main() -> Result<(), v2::Error> {
let text = "MSH|^~\\&|LAB||EPIC||20260814080000||ORU^R01|MSG00042|P|2.5\r\
PID|1||241900||EVERYWOMAN^EVE";
let message = v2::parse(text)?;
assert_eq!(message.structure_id(), "ORU_R01");
assert_eq!(message.get("PID-5.1")?.as_deref(), Some("EVERYWOMAN"));
println!("ok");
Ok(())
}And the same for the command-line tool:
$ printf 'MSH|^~\\&|LAB||EPIC||20260814080000||ORU^R01|1|P|2.5\rPID|1||241900\r' \
| hl7-v2 --query PID-3
241900If either works, go to the quick start. If neither does, the troubleshooting page covers the failures people actually hit.