LCM Logo

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

LanguageExchange (FHIR/HL7v2/CDA)Data models (OMOP/CDISC)TerminologiesVerdict
RAdequateExcellentGoodThe strongest choice for research
PythonExcellentAdequateExcellentThe strongest choice for engineering and NLP
JavaExcellentAdequateExcellentWhere the reference implementations live
TypeScriptGood (FHIR only)NoneNoneApp development against FHIR APIs
SASNoneGood (PCORnet, CDISC)NoneLegacy, but unavoidable in trials and PCORnet
JuliaNoneThinNoneNot yet a realistic primary choice
RustThinNoneNoneNot 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.

install.R
# 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.

install.sh
# 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 pathling

Note 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.

install.sh
pnpm add @medplum/core @medplum/fhirtypes fhirpath fhir-kit-client
pnpm add -D @types/fhir
pnpm add -g fsh-sushi   # authoring implementation guides

Medplum 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

ToolPurpose
HL7 ValidatorThe official validator jar for FHIR and CDA. Validates against profiles, not just structure
sushiCompile FHIR Shorthand into an implementation guide
InfernoONC's conformance test kit — what US certification is measured against
SyntheaGenerate synthetic patients with full histories; exports FHIR, C-CDA, and CSV
ETL-SyntheaLoad Synthea output into an OMOP CDM
BroadseaDocker deployment of the whole OHDSI stack, ATLAS included
AthenaDownload the OMOP vocabulary tables. You will need an account
SnowstormSNOMED International's terminology server, with a FHIR API
Mirth ConnectThe de facto HL7 v2 interface engine — check current licensing
xmllint, SaxonC-CDA schema and Schematron validation

Getting data to work on

In rough order of how quickly you can be running code:

  1. Eunomia (R) — a pre-built OMOP CDM in a local SQLite or DuckDB file. Working queries in about a minute, no ETL, no credentials
  2. Synthea — synthetic patients with complete longitudinal histories, exported to FHIR, C-CDA, or CSV. The best option for exercising an exchange-format pipeline
  3. 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
  4. MIMIC-IV and eICU (PhysioNet) — real, de-identified ICU data. Requires credentialing and a training course, and there is an OMOP-formatted release
  5. 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.