Health-data infrastructure in Rust, built on open standards.

FerroHEALTH is the family behind five servers that do one job each and reach each other only over published protocols: a record server that speaks openEHR, a bridge that carries a record out to FHIR and to the OMOP Common Data Model and brings HL7 Version 2 messages in, a gateway that queries the record where another organisation holds it, a patient index that says who the patient is, and a terminology server that speaks HL7 FHIR. No JVM, no language runtime, no search cluster. One more is planned: what happens next.

Ferro is ferrum, iron. Rust is an oxide of it, which is the language every one of them is written in.

The products

Five products, each in its own lane

Each one is its own server, repository, release train and site, and reaches the others only over a published protocol. A product never carries another's job: when it needs one, it calls that server as a client. Run the one you need; nothing here requires the others. FerroFORMS, the form builder, is paused and listed last.

FerroEHR

The record
v5.5.0

An openEHR Clinical Data Repository. Applications store and query structured health records through a vendor-neutral REST API and the Archetype Query Language, so the record outlives the application that wrote it.

  • The openEHR REST API and AQL, generated from the official machine-readable models
  • Contribution-atomic versioning, attestations and per-version signatures
  • One self-contained binary on PostgreSQL, no JVM in the write path
  • Every conformance claim run against the live server each release
  • The record and nothing else: FHIR and OMOP are FerroBRIDGE's, federation FerroFED's, identity FerroPIX's

FerroTERM

The meaning
v0.4.0

An HL7 FHIR terminology server. It answers the FHIR terminology API from one static binary over a memory-mapped index built once per release, which is what lets a full SNOMED CT edition run on ordinary hardware.

  • SNOMED CT, LOINC, ICD-10, ICD-11, RxNorm, UCUM and any FHIR CodeSystem; its site carries the full list
  • Several FHIR releases from one binary, each under its own path, and a web viewer in the same binary
  • No JVM, no Elasticsearch, no database to run
  • Every published figure rendered from a committed benchmark record

FerroBRIDGE

The way out
v0.0.18

A bridge from openEHR to two targets: HL7 FHIR, and the OMOP Common Data Model for research. It also takes clinical HL7 Version 2 messages in and maps them through HL7's Version 2 to FHIR guide. Mappings are specification-conformant YAML validated against published schemas, never hand-coded per resource or per table.

  • FHIRconnect for the FHIR side, OMOCL for the OMOP side
  • Its own process beside any CDR it reaches over ITS-REST, never a plugin
  • A FHIR face that stores nothing, an MLLP listener for HL7 Version 2, and a batch load that writes typed rows
  • Publishes fhir-types and the terminology client ferrobridge-term, for every product to use
  • Every decision carries its citation, in the architecture document and on the tracker

FerroFED

Where else the record is
v0.0.15

The federation gateway: the openEHR Federation Tier with AQL, EHDS cross-border exchange and MyHealth@EU. It queries the record where it lives, and it keeps no second copy that could compete with the source. Who the patient is, it asks FerroPIX.

  • A transparent ITS-REST intermediary: a client sends an ordinary AQL query and never learns it was federated
  • The patient is resolved first, at FerroPIX over PIXm, so no directly identifying identifier travels in a query
  • Standard AQL to each node, the local FerroEHR or a remote CDR, scoped to that node's own EHR id and merged with its provenance
  • Its own process beside the CDR, with ITS-REST and FHIR faces for its clients, and never a plugin

FerroPIX

Who the patient is
v0.0.14

A Master Patient Index. Every organisation issues its own identifiers for the same person, and records move, so one service holds the cross-reference and the record's location and answers the question every other component starts with. It runs as a released server, and it publishes its identity crates for every product to use.

  • IHE PIXm, PDQm and PMIR, and the HL7 Version 2 identity feed and queries (ITI-8, ITI-9, ITI-21) over MLLP
  • Mints the pseudonym a clinical record carries, so the record holds no directly identifying identifier
  • Identity is its job alone: FerroFED asks it where a patient's records are, and FerroEHR is to look an EHR's subject up there as a client
  • Publishes the IHE identity profiles as the ihe-iti crate and the Dutch Generic Functions as nl-generic-functions, for every product to use

FerroFORMS

The way in, paused
v0.1.1

An openEHR form builder and renderer. It compiles an operational template into a form, renders it for a clinician, and turns what they type back into a COMPOSITION, so the last mile between a clinical model and a person is not hand-built per form. Its development is paused.

  • Fields derived from the Reference Model type at each template node
  • Hand-authored layout in a separate overlay, so a template revision does not destroy it
  • Any openEHR CDR over ITS-REST, never a plugin inside one
  • The round trip to a real CDR runs in CI on every pull request

One more, planned

The products above carry the record. This one will work beside it: what happens next. It has a name, a registered domain and a repository that opens with its licence and its mark. The badge on its card is read from GitHub when this page is assembled and says when its code last moved. A planned product joins the products above when it publishes a first release.

FerroTASK

What happens next

The task planning and decision support server. A record says what has happened to a patient; a care pathway says what should happen next, who does it, and what to decide when a result comes in. FerroTASK runs that half, against the record FerroEHR keeps.

  • openEHR Task Planning, from the PROC component: plans for clinical work, with the Decision Language for the rules inside them
  • GDL2, the guideline language of the openEHR CDS component, evaluated against archetype and template paths
  • A client of the CDR: it reads what has happened over AQL and commits the state of each plan back, so it keeps no clinical record of its own
GitHub ferrotask.eu code moved 2026-10-31
Shared libraries

What the products are built from

Four libraries hold what every product would otherwise write for itself. They are Rust crates on crates.io, released from their own repositories under the same licence as the products, and a product compiles them in. They carry the work every product shares and never a product's domain. None of them is a server, and none of them runs on its own. The protocol clients and models stay with the product that owns the protocol: fhir-types and ferrobridge-term with FerroBRIDGE, ihe-iti and nl-generic-functions with FerroPIX, and the openehr-* crates with FerroEHR.

FerroAUTH

ferrohealth-smart, ferrohealth-authz
ferrohealth-smart-v0.8.8

Authentication and the policy decision, renamed from FerroSMART. ferrohealth-smart is the SMART App Launch and OAuth 2.0 resource server each product runs in its own process: it checks the access tokens a product is handed against the deployment's own authorization server, and it issues no token and holds no signing key. ferrohealth-authz makes the policy decision, with its first usable release in preparation.

  • SMART on openEHR and SMART on FHIR scopes, side by side in one token, and the authenticated subject with its scopes and roles
  • Machine authentication: HTTP Basic and the OAuth 2.0 client credentials grant
  • The policy decision: ABAC, Cedar, or a remote PDP
  • Used by FerroEHR, FerroTERM, FerroBRIDGE, FerroFED and FerroPIX

FerroAUDIT

ihe-atna, ehds-logging
v0.3.3

The audit trail and the EHDS access record, written once for the family, so a product that sends its audit records through it implements no audit of its own.

  • The whole IHE ATNA and BALP audit trail: the Record Audit Event (ITI-20) sent through a store-and-forward spool, forwarded and retrieved
  • The record of every access to electronic health data that the EHDS Regulation asks of an EHR system
  • Used by FerroEHR, FerroFED and FerroPIX

FerroUI

ferrohealth-ui
v0.6.6

The one source for the user interface of every operator console, so every product's console reads and behaves the same way in its own product's colours. FerroUI leads: a console takes its components, stylesheet and design from the library, and the consoles move onto the library's rebuild together, in one rollout, once the last release of that rebuild ships.

  • Leptos components, one table model and a theme per product, light and dark
  • Every component aimed at WCAG 2.2 Level AA, with a contrast test over every colour pairing
  • Every console is reactive: a link, a form or an action never reloads the whole page, with WebAssembly as the normal path
  • Used by the consoles of FerroEHR, FerroTERM, FerroBRIDGE and FerroFED

FerroSYS

ferrohealth-* system crates
code moved 2026-11-04

The system plumbing every product shares, written once as crates: secrets and redaction, configuration, logging and OpenTelemetry, health, the HTTP stack and its drain, and the usage report. It is a set of crates like FerroAUTH and FerroAUDIT, and never a control plane or a central service.

  • ferrohealth-secret, -config, -telemetry, -health, -server and -usage-report
How they fit

What calls what

Every arrow is a published specification, so any one of them can be swapped for another implementation of the same standard. Solid is a server you can run today; dashed is one not running yet. The band under the frame is the shared libraries, which run inside the products and are called by nothing over the network.

Five products reach each other only over published protocols. FerroEHR, the openEHR CDR, is reached over the openEHR ITS-REST API and AQL, which any application can call directly, and it validates coded values against FerroTERM, the FHIR terminology server, as a client. FerroBRIDGE reads FerroEHR over ITS-REST, calls FerroTERM to look up and translate codes, exchanges resources with HL7 FHIR over its FHIR face in both directions, receives clinical HL7 Version 2 messages over MLLP, and writes typed rows into an OMOP Common Data Model database over SQL. FerroFORMS, the form builder, is paused and drawn in grey: a clinician uses it in a browser, and it expands value sets against FerroTERM and commits compositions to FerroEHR over ITS-REST. Three services frame the data path: FerroPIX, the Master Patient Index, owns identity and the IHE profiles, and FerroEHR is to look the subject of each EHR up there as a client over PIXm and PDQm; applications send FerroFED, the federation gateway, an ordinary AQL query, and it asks FerroPIX where the record is, then dispatches the query to FerroEHR and to other organisations' openEHR CDRs as federation nodes; and FerroTASK, the planned task planning and decision support server, drawn dashed, reads FerroEHR over ITS-REST and AQL and commits the state of each plan back to it. Each server checks the access tokens it is handed against the deployment's own authorization server, so no FerroHEALTH service holds the key every server depends on. A frame around the seven marks one FerroHEALTH instance serving one tenant; clinicians, applications, FHIR, HL7 Version 2 senders, OMOP and other organisations sit outside it. Under the frame, a band holds the four shared libraries the products are built from, which never run on their own: FerroAUTH authenticates callers and makes the policy decision, issuing no token, FerroAUDIT writes the audit trail and the EHDS access record, FerroUI holds the components of the operator consoles, every one of them reactive, and FerroSYS holds the system plumbing every product shares, from secrets and configuration to telemetry, health, the HTTP stack and the usage report.

The frame is one FerroHEALTH instance serving one tenant: the eight inside are the family, and everything outside is a caller, a target or another organisation. Every product is single-tenant: one instance serves one organisation, and an organisation that serves several runs several instances. Left to right is the order data moves. An arrowhead points at what is called or written to, and the FHIR side carries one at both ends because the bridge reads openEHR out to FHIR and writes FHIR back in. The other three servers call a FHIR terminology server, for three different reasons: FerroFORMS, now paused, to expand the value set behind a coded field so the form can offer the codes it admits, FerroEHR to validate a coded value at commit time, with $expand configured in its place against a server that does not offer $validate-code, and FerroBRIDGE to resolve a display, translate a code and validate one. That seam is the FHIR terminology API, so FerroTERM fills it and so does any other implementation. The facade speaks the FHIR release FHIRconnect's mappings name, and FerroBRIDGE's site says which. HL7 Version 2 senders reach the bridge over MLLP, and it maps each message through HL7's Version 2 to FHIR guide into the CDR. OMOP is a database schema, so its edge names no protocol: the OMOCL mappings compile to SQL that writes typed rows into the CDM tables.

The dashed box is FerroTASK, the planned product, and the grey box is FerroFORMS, which is paused. No authorisation server is drawn: each server is its own SMART App Launch resource server, through FerroAUTH's ferrohealth-smart, and checks the access tokens it is handed against the deployment's own authorization server, because one central service would hold the signing key every server's access depends on. Identity and the IHE profiles are FerroPIX's alone, and FerroEHR implements none of them: it is to look the subject of an EHR up at FerroPIX as a client, over PIXm and PDQm, so the subject its EHR_STATUS carries can be the pseudonym FerroPIX mints. An application sends FerroFED an ordinary AQL query and never learns it was federated: the gateway asks FerroPIX where the record is, then sends standard AQL to each node, the local FerroEHR or another organisation's CDR, and merges what comes back. An application that opens a record asks FerroPIX the same question; FerroFORMS receives the EHR it is launched with and asks nobody. Every operator console is built on FerroUI and is reactive. FerroSYS sits with the other shared libraries: its crates carry the secrets, configuration, telemetry, health, HTTP stack and usage report of each product, inside that product. FerroTASK reads the record over AQL and commits the state of each plan back to it, like any other client of the CDR. The audit trail goes to an Audit Record Repository the deployment runs, through FerroAUDIT, which FerroEHR, FerroFED and FerroPIX use. Which release of each standard a product implements is on that product's site, rendered from its own pins.

What the family holds in common

The same four commitments in every repository

The products differ in what they do. They are built, licensed and evidenced the same way.

The standard is the interface

openEHR for the record, HL7 FHIR for exchange and terminology, OMOP for research. Where a specification publishes a machine-readable model, the code is generated from it, so a specification update is a regeneration.

One licence, no open-core tier

Every product is source-available under the Business Source License 1.1, with each capability in one repository and nothing held back for a paid edition. Free for non-commercial production; other production use needs a commercial licence, and each version becomes Apache 2.0 four years after it is published. What that means for you.

Measured, never typed

Conformance verdicts and performance figures are rendered into these sites from records committed to the repository, and a check fails the build when a page and its records disagree. Every number on these sites comes from a run.

One binary to operate

Each server is a single self-contained Rust binary in a minimal distroless image: no application server, no language runtime to patch, and no garbage-collection pause in the request path. What you deploy is what you read.

Ecosystem

What the products speak

Each product's own site carries the exact versions it implements and the evidence for each claim.

Records

openEHR ITS-REST AQL Reference Model ADL / OPT PostgreSQL

Terminology

HL7 FHIR SNOMED CT LOINC ICD-10 / ICD-11 RxNorm UCUM

Exchange and research

FHIRconnect OMOCL OMOP CDM IHE PIX / PDQ / PMIR HL7 Version 2 / MLLP AMQP S3

Operations

OIDC / Keycloak SMART App Launch IHE ATNA / BALP audit OpenTelemetry Prometheus Kubernetes / Helm
Quick start

The whole stack, from one file

Nothing to check out. Each command below names a product's latest release, so it runs the same after the next one is cut. Each product's site carries the full installation, the configuration, and the licensing each code system needs.

shell
# FerroFORMS's release compose file starts FerroFORMS, FerroEHR with its
# PostgreSQL, and FerroTERM. Three products, three licences; the file's
# header says what the demo profile is for.
$ curl -LO https://github.com/FerroHEALTH/FerroFORMS/releases/latest/download/compose.yaml
$ FERROCHART_CDR_URL=http://ferroehr:8080/ferroehr/rest/openehr \
  FERROCHART_TERM_URL=http://ferroterm:8080/r4 \
  docker compose --profile demo up
# then open http://localhost:8080

# FerroTERM alone. The image serves UCUM and the registries with no
# configuration, and its viewer is at /ui.
$ docker run --rm -p 8080:8080 ghcr.io/ferrohealth/ferroterm:0.4.0
# then open http://localhost:8080/ui
Status

Where each product is

Three figures per product, read from its repository on GitHub when this page is assembled: the latest release it has published, the day that release went out, and the day its code last moved. None of them is typed by hand, and the page is rebuilt several times a day, so a release cut this morning is here by this afternoon. What a release contains is on the product's own site. FerroFORMS is paused and keeps its row. The shared libraries show their release on their cards and have no row here.

Latest release, its date, and the last push per product, read from the GitHub API when this page was assembled.
Product Does Latest release Published Last change Licence
FerroEHR Stores and queries the record v5.5.0 BUSL-1.1
FerroTERM Answers what a code means v0.4.0 BUSL-1.1
FerroBRIDGE Carries the record onward v0.0.18 BUSL-1.1
FerroFED Queries the record where it lives v0.0.15 BUSL-1.1
FerroPIX Says who the patient is v0.0.14 BUSL-1.1
FerroFORMS Takes the record down; paused v0.1.1 BUSL-1.1
Licensing

Do you need a commercial licence?

Every product is source-available under the Business Source License 1.1, which is not an OSI-approved open-source licence. The terms that apply to you are in each repository's own LICENSE, which names its Licensor, its Licensed Work, its Additional Use Grant and its Change Date. This page summarises them for evaluators, and each LICENSE is the authority.

The same answer holds for every product. Each product's LICENSE states it for that product.
What you are doing What you need Why
Reading, building, modifying or redistributing the source Free The licence grants it without a fee and without asking anyone.
Development, testing, evaluation, prototyping Free All non-production use is granted.
Production use for Non-Commercial Purposes Free Personal use, academic or scientific research, teaching, and use by a non-profit organisation or public body that is not in the course of a business, does not deliver a service for payment, and is not for commercial advantage.
A hospital, clinic or care provider running it for its patients Delivering health care, or any other service for payment, is production use outside the grant.
A vendor or integrator, or any company running it in production Production use in the course of a business is outside the grant.
Offering it, or a work derived from it, to third parties as a hosted, managed or embedded service Excluded from the grant in every case, whoever you are.
Selling, sublicensing or otherwise distributing it for a fee, on its own or inside another product Excluded from the grant in every case, whoever you are.

FerroFORMS

Licensor Cadasto B.V. The Licensed Work is FerroFORMS, each version as published on GitHub.

FerroFORMS LICENSE

FerroEHR

Licensor Cadasto B.V. The Licensed Work is FerroEHR, each version as published on GitHub.

FerroEHR LICENSE

FerroTERM

Licensor Cadasto B.V. The Licensed Work is FerroTERM, each version as published on GitHub. The code systems it serves are licensed by their owners, and it ships none of their content.

FerroTERM LICENSE

FerroBRIDGE

Licensor Cadasto B.V. The Licensed Work is FerroBRIDGE, each version as published on GitHub.

FerroBRIDGE LICENSE

FerroPIX

Licensor Cadasto B.V. The Licensed Work is FerroPIX, each version as published on GitHub.

FerroPIX LICENSE

FerroFED

Licensor Cadasto B.V. The Licensed Work is FerroFED, each version as published on GitHub.

FerroFED LICENSE

FerroTASK

Licensor Cadasto B.V. The Licensed Work is FerroTASK, each version as published on GitHub.

FerroTASK LICENSE

The Change Date. Each version becomes available under the Apache License 2.0, its Change License, four years after that version is published. The change applies per version, so a version you run today gets there on its own date.

The published crates are listed by their product. Some products publish Rust crates on crates.io, some under Apache-2.0 so any Rust project can use them with no licence conversation, and some under the same Business Source License as the server. Which crate carries which licence, and the terms every vendored third-party file keeps, is on each product's own licensing page: FerroFORMS's, FerroEHR's, FerroTERM's, FerroBRIDGE's, FerroFED's and FerroPIX's. A crate list typed here would be wrong within a release.

The shared libraries carry the same licence. FerroAUTH, FerroAUDIT, FerroUI and FerroSYS are under the Business Source License 1.1 with Cadasto B.V. as Licensor, so compiling one into a product changes nothing in the answer above. Each repository's LICENSE holds its parameters: FerroAUTH's, FerroAUDIT's, FerroUI's and FerroSYS's.

The software licence and the content are two questions. FerroTERM's page answers the one its evaluators arrive with. SNOMED CT is licensed by SNOMED International, LOINC by Regenstrief, ICD by the WHO and RxNorm by the NLM. FerroTERM ships none of that content, and a deployment brings the release it is licensed for.

Getting a commercial licence. Companies and care providers building on these products are wanted here, and the commercial licence is the normal path for them. Cadasto B.V., the Licensor, handles the business side of every product, the commercial licence included: write to info@cadasto.com or use cadasto.com/contact. Technical questions go to the maintainer named in that product's MAINTAINERS.md.

Send the improvements back

The one thing the family asks, and cannot require. A private fork pays for the whole maintenance surface alone; upstreamed, the same work is maintained once for everyone, and a defect found once gets fixed everywhere. That is what clinical software should do.