Skip to content

dnlbox/fhir-test-data

Repository files navigation

fhir-test-data

CI CodeQL npm License: MIT

Generate valid FHIR R4 / R4B / R5 test resources with country-aware identifiers — from the CLI, a TypeScript library, or any tool that reads from a pipe.

What is FHIR?

FHIR (Fast Healthcare Interoperability Resources) is the modern standard for exchanging healthcare data, published by HL7. This tool generates FHIR JSON resources — the building blocks of healthcare APIs. Learn more at hl7.org/fhir


Why this exists

FHIR development requires realistic test data, but building it by hand is tedious and error-prone. Most teams either copy production data (a compliance risk) or write custom generators that hardcode US-centric identifiers — useless if your system needs to handle UK NHS numbers, Dutch BSNs, Korean RRNs, or Brazilian CPFs.

fhir-test-data generates structurally valid FHIR resources across 14 locales, with identifiers that pass each country's official check-digit algorithm. Clinical resources use real LOINC codes with values in realistic clinical ranges and HL7-consistent units of measurement, and SNOMED CT codes for conditions — so the data makes sense medically, not just structurally. All output is seeded and deterministic — the same seed always produces the same data, anywhere it runs.

Supported resource types: Patient, Practitioner, PractitionerRole, Organization, Observation, Condition, AllergyIntolerance, MedicationStatement, Encounter, DiagnosticReport, and Bundle.


Quick start

CLI

No install required — run directly with npx:

npx fhir-test-data generate patient --locale uk --count 5 --seed 42

Or install globally for repeated use:

pnpm add -g fhir-test-data
# or
npm install -g fhir-test-data

# Generate 5 UK patients to stdout
fhir-test-data generate patient --locale uk --count 5 --seed 42

# Generate a full bundle to a fixtures directory
fhir-test-data generate bundle --locale au --seed 1 --output ./fixtures/

Library

pnpm add fhir-test-data
import { createPatientBuilder, createBundleBuilder } from "fhir-test-data";

const [patient] = createPatientBuilder().locale("uk").seed(42).build();

const [bundle] = createBundleBuilder()
  .locale("us")
  .seed(42)
  .type("transaction")
  .clinicalResourcesPerPatient(5)
  .build();

CLI-first, pipe-friendly, AI-friendly

The CLI writes to stdout by default — making it a natural fit for shell pipelines, scripting, and AI-assisted workflows. Combine it with jq, FHIR validators, load testing tools, or large language models without any glue code.

# Inspect a generated resource with jq
fhir-test-data generate patient --locale uk --seed 42 | jq '.identifier[0]'

# Stream NDJSON into a validator or ingest tool
fhir-test-data generate patient --count 100 --format ndjson | your-fhir-validator --stream

# POST to a FHIR server
fhir-test-data generate patient --locale nl --seed 1 | \
  curl -s -X POST https://your-fhir-server/Patient \
    -H "Content-Type: application/fhir+json" -d @-

# Ask an AI assistant to explore or explain a generated bundle
fhir-test-data generate bundle --locale kr --seed 5 | \
  llm "summarise the clinical findings in this FHIR bundle"

# Generate NDJSON for bulk load testing
fhir-test-data generate patient --locale us --count 1000 --format ndjson --no-pretty \
  > patients.ndjson

# Loop across locales in a CI step
for locale in us uk au de fr nl; do
  fhir-test-data generate bundle --locale $locale --seed 1 --output "./fixtures/$locale/"
done

Because output goes to stdout by default, there is nothing to configure — drop it into any pipeline that reads JSON or NDJSON.


Supported locales

14 locales with check-digit-validated identifiers and locale-appropriate names, addresses, and phone formats:

Country Code Patient identifiers Algorithm Practitioner identifiers
United States us SSN, MRN Format validation NPI (Luhn)
United Kingdom uk NHS Number Modulus 11 GMC Number, GMP Number
Australia au IHI, Medicare Luhn HPI-I (Luhn)
Canada ca Ontario HCN Format validation
Germany de KVID-10 Format validation LANR (Modulus 10)
France fr NIR Modulus 97 RPPS (Luhn)
Netherlands nl BSN 11-proef UZI Number
India in Aadhaar, ABHA Verhoeff
Japan jp Hospital MRN Format validation Doctor License
South Korea kr RRN Format + gender encoding MOHW Doctor License
Mexico mx CURP Format validation Cédula Profesional
Brazil br CPF Modulus 11 variant CRM
Singapore sg NRIC / FIN Check letter SMC Registration
South Africa za SA ID Number Luhn HPCSA Registration

Identifier validation is baked in — generated values always pass the official algorithm for their country. The library also includes tools like fhir-resource-diff for structural comparison and validation of generated fixtures.


Clinical code quality

Observations use real LOINC codes with valueQuantity in clinically plausible ranges and HL7-consistent units of measurement (e.g. mm[Hg] for blood pressure, kg/m2 for BMI). Conditions use SNOMED CT codes. AllergyIntolerance resources include coded substances. The goal is data that makes sense to a clinician, not just data that passes a schema validator.


Seeded determinism

The same seed produces identical output on any machine, any Node version, any CI environment:

fhir-test-data generate patient --locale uk --seed 42 > a.json
fhir-test-data generate patient --locale uk --seed 42 > b.json
diff a.json b.json  # empty — identical output

Reliable for snapshot tests, golden file comparison, and regression test fixtures.


Multi-version FHIR support

All builders target R4 (default), R4B, or R5. R5 structural adaptations are applied automatically — MedicationStatement becomes MedicationUsage, and AllergyIntolerance.type becomes a CodeableConcept.

fhir-test-data generate bundle --locale us --seed 1 --fhir-version R5

Bundle builder

The Bundle builder composes all resource types into a single FHIR Bundle with automatic reference wiring using urn:uuid: format:

const [bundle] = createBundleBuilder()
  .locale("uk")
  .seed(1)
  .type("transaction")
  .clinicalResourcesPerPatient(5)
  .build();

Each bundle includes: Patient, Organization, Practitioner, PractitionerRole, and N clinical resources (Observations, Conditions, AllergyIntolerance, MedicationStatement). All internal references are consistent: Observation.subject points to the Patient, Observation.performer[0] to the Practitioner, and Patient.managingOrganization to the Organization.


Fault injection

Generate intentionally invalid resources for testing validation pipelines and error handlers:

import { withFault } from "fhir-test-data/faults";

const [invalid] = withFault(
  createPatientBuilder().locale("uk").seed(42),
  "missing-resource-type"
).build();

Comparison with Synthea

Synthea is a fantastic open-source patient generator that produces clinically realistic longitudinal patient histories — disease progression, care pathways, medication histories — and has been hugely valuable for healthcare research and simulation work.

fhir-test-data serves a different need: TypeScript-native, internationally correct, deterministic fixtures for developer testing workflows.

fhir-test-data Synthea
Language TypeScript Java
Usage Library + CLI Standalone tool
International identifiers 14 locales US-only
Deterministic output Yes (seeded PRNG) Partial
TypeScript integration Native types JSON only
Clinical realism Coded LOINC/SNOMED values High (disease progression)
Browser-safe core Yes No
Pipe-friendly CLI Yes No

Use fhir-test-data when you need TypeScript-native, internationally correct, deterministic fixtures for unit tests, integration tests, CI pipelines, or FHIR server load testing. Use Synthea when you need clinically realistic patient histories with disease progression for research or simulation.


The FHIR TypeScript ecosystem

fhir-test-data is part of a small family of tools for FHIR developer workflows:

Tool Purpose
fhir-test-data (this package) Generate valid FHIR fixtures across 14 locales
fhir-resource-diff Validate, diff, and compare individual FHIR JSON resources
fhir-capability-analyzer Fetch, analyze, and compare FHIR server CapabilityStatements

Using them together:

# Generate a patient fixture and validate it in one step
fhir-test-data generate patient --locale uk --seed 42 | \
  fhir-resource-diff validate - --fhir-version R4

# Create regression fixtures, commit them, then check for drift in CI
fhir-test-data generate bundle --locale us --seed 1 --output ./fixtures/
fhir-resource-diff compare ./fixtures/Bundle-001.json ./baseline/Bundle-001.json \
  --preset metadata --exit-on-diff

# Generate fixtures, validate them, then check what the server supports
fhir-test-data generate patient --locale au --seed 1 | \
  fhir-resource-diff validate - --fhir-version R4
fhir-capability-analyzer analyze https://your-fhir-server.example.com

Development

Prerequisites

  • Node.js >= 20
  • pnpm >= 9

Setup

git clone https://github.com/dnlbox/fhir-test-data.git
cd fhir-test-data
pnpm install

Common scripts

Script Purpose
pnpm cli -- generate patient --seed 1 Run CLI from source
pnpm test Run tests
pnpm test:watch Run tests in watch mode
pnpm typecheck TypeScript type checking
pnpm lint ESLint
pnpm build Production build (tsup)

Documentation

Full API reference, locale details, fault injection guide, and VitePress documentation at dnlbox.github.io/fhir-test-data.

See CONTRIBUTING.md for contribution guidelines and CHANGELOG.md for version history.

About

Generate valid FHIR R4/R4B/R5 test data with country-aware identifiers — CLI, TypeScript library, pipe-friendly, AI-friendly

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors