Tooling by language
What to install for health data work in R, Python, Julia, TypeScript, Rust, and at the command line.
Sources last verified
The per-format pages give the package for each individual standard. This page answers the question that comes first in practice: given the language I work in, what can I actually do?
The honest summary
| Language | Exchange (FHIR/HL7v2/CDA) | Data models (OMOP/CDISC) | Terminologies | Verdict |
|---|---|---|---|---|
| R | Adequate | Excellent | Good | The strongest choice for research |
| Python | Excellent | Adequate | Excellent | The strongest choice for engineering and NLP |
| Java | Excellent | Adequate | Excellent | Where the reference implementations live |
| TypeScript | Good (FHIR only) | None | None | App development against FHIR APIs |
| SAS | None | Good (PCORnet, CDISC) | None | Legacy, but unavoidable in trials and PCORnet |
| Julia | None | Thin | None | Not yet a realistic primary choice |
| Rust | Thin | None | None | Not yet a realistic primary choice |
The division between R and Python is unusually clean, and it is worth naming plainly: R is better for analysis, Python is better for plumbing. The OHDSI ecosystem has no Python equivalent, and clinical NLP has no R equivalent. Projects that need both should use both rather than forcing one to cover the gap — the interop cost is far lower than the cost of the missing library.
R
The best-supported language for observational health research, almost entirely because of OHDSI and pharmaverse.
# OMOP CDM
install.packages(c(
"CDMConnector", "DatabaseConnector", "SqlRender", "CodelistGenerator",
"CohortGenerator", "IncidencePrevalence", "CohortSurvival", "DrugUtilisation",
"OmopSketch", "Eunomia", "omopgenerics", "PatientProfiles", "DataQualityDashboard"
))
# Clinical trials (CDISC)
install.packages(c("admiral", "sdtm.oak", "metacore", "metatools", "xportr",
"datasetjson", "logrx", "haven"))
# Terminologies and phenotyping
install.packages(c("icd", "comorbidity", "touch", "Rdiagnosislist", "medicalrisk",
"ontologyIndex", "ontologySimilarity"))
# Exchange formats and data capture
install.packages(c("fhircrackr", "REDCapR", "redcapAPI"))
# Database backends
install.packages(c("DBI", "duckdb", "dbplyr", "arrow"))Two things to know before you start. DatabaseConnector uses JDBC, so you need a working Java
installation and downloaded drivers — this is the most common setup failure. And CDMConnector
returns lazy dbplyr tables, so your dplyr pipeline is translated to SQL and executed in the
database; nothing is pulled into memory until you collect().
Python
The best choice for anything involving FHIR clients, clinical text, or production data pipelines.
# FHIR
uv pip install fhir.resources fhirpy fhirclient fhirpathpy
# HL7 v2
uv pip install hl7apy hl7
# Clinical NLP and terminologies
uv pip install medcat scispacy medspacy negspacy quickumls PyMedTermino
# ICD and comorbidity scoring
uv pip install simple-icd-10 comorbidipy
# CDISC and SAS interchange
uv pip install pyreadstat xport odmlib cdisc-rules-engine
# OMOP
uv pip install pyomop ohdsi-common ohdsi-database-connector ohdsi-sqlrender
# Population-scale FHIR analytics
uv pip install pathlingNote that the ohdsi-* packages are JPype bridges to the R and Java implementations, not native
ports — they need a JVM and they lag upstream. If OMOP analysis is the centre of your project,
that is an argument for doing it in R.
For de-identification, presidio-analyzer and
presidio-anonymizer (Microsoft) are the general-purpose PII tools, and
philter-ucsf targets clinical notes specifically. Treat
all of them as a first pass requiring human review, never as a compliance guarantee.
Julia
Limited but not empty. JuliaHealth maintains genuine OMOP packages —
OMOPCDMCohortCreator and OMOPCDMDatabaseConnector are in the General registry — and
ReadStatTables.jl and SASLib.jl read SAS transport files.
There is nothing for FHIR, HL7 v2, or the terminologies. For those, call a service over HTTP or shell out. Julia is a reasonable choice for the modeling stage of a project whose data engineering happens elsewhere; it is not yet a reasonable choice for the data engineering itself.
TypeScript
Strong for FHIR and essentially absent everywhere else — which is the right shape, given that its niche is applications talking to FHIR APIs.
pnpm add @medplum/core @medplum/fhirtypes fhirpath fhir-kit-client
pnpm add -D @types/fhir
pnpm add -g fsh-sushi # authoring implementation guidesMedplum is worth knowing beyond its client library: it is an open-source FHIR server and app platform, and is often the fastest way to a working FHIR backend for development.
Rust
Two areas have real entries and the rest has nothing.
fhir-sdk is actively maintained with models and a client for
R4B and R5; hl7-parser and
hl7-mllp-codec cover v2 parsing and transport.
Choose Rust here when you are building a high-throughput interface component with a narrow job — an
MLLP listener, a bulk NDJSON transformer — not for analysis. Check the last release date before
committing: fhirbolt looks plausible in search results but has been quiet since 2023.
Command line and services
| Tool | Purpose |
|---|---|
| HL7 Validator | The official validator jar for FHIR and CDA. Validates against profiles, not just structure |
sushi | Compile FHIR Shorthand into an implementation guide |
| Inferno | ONC's conformance test kit — what US certification is measured against |
| Synthea | Generate synthetic patients with full histories; exports FHIR, C-CDA, and CSV |
| ETL-Synthea | Load Synthea output into an OMOP CDM |
| Broadsea | Docker deployment of the whole OHDSI stack, ATLAS included |
| Athena | Download the OMOP vocabulary tables. You will need an account |
| Snowstorm | SNOMED International's terminology server, with a FHIR API |
| Mirth Connect | The de facto HL7 v2 interface engine — check current licensing |
xmllint, Saxon | C-CDA schema and Schematron validation |
Getting data to work on
In rough order of how quickly you can be running code:
Eunomia(R) — a pre-built OMOP CDM in a local SQLite or DuckDB file. Working queries in about a minute, no ETL, no credentials- Synthea — synthetic patients with complete longitudinal histories, exported to FHIR, C-CDA, or CSV. The best option for exercising an exchange-format pipeline
- Public FHIR sandboxes — HAPI's public server, SMART Health IT's sandbox, and the major EHR vendor developer programs all expose R4 endpoints with test data
- MIMIC-IV and eICU (PhysioNet) — real, de-identified ICU data. Requires credentialing and a training course, and there is an OMOP-formatted release
- All of Us, N3C — large real-world US datasets in OMOP, accessible through a controlled workbench after approval
Steps 4 and 5 involve real patient data under a data use agreement. The agreement typically restricts where the data may be stored, prohibits re-identification attempts, and forbids pasting records into external services — which includes LLM APIs. Read it before you write any code, not after.
A note on scale
Health datasets are wide and long — a national OMOP instance can hold billions of rows in
measurement alone — but the queries are usually simple joins and aggregations. That profile suits
columnar engines exactly.
DuckDB has become the default for single-machine work in both R and Python: it reads Parquet
directly, handles datasets larger than memory, and both CDMConnector and dbplyr target it well.
Reach for Spark or a cloud warehouse when the data genuinely does not fit on one machine, not by
default. See DuckDB and
tabular operations for the general tooling.