synthea-healthcare-data
Author and run Synthea (MITRE's open-source synthetic patient population simulator) to produce HIPAA-safe synthetic medical records for testing health IT systems. Covers Gradle build, population-size and state-specific generation, FHIR R4 / STU3 / DSTU2 / C-CDA / CSV / CPCDS output formats, disease-module customisation, and the lifecycle-simulation approach (birth-through-death patient journeys with realistic demographics). Use when testing FHIR servers, EHR integrations, claims processing, or any health IT system that needs realistic patient records without HIPAA exposure (distinct from faker-synthetic-data which is generic; this is health-domain-specific).
Install with skills.sh (any agent)
npx skills add testland/qa --skill synthea-healthcare-datasynthea-healthcare-data
Overview
Synthea is MITRE's open-source synthetic-patient population simulator that generates realistic but fictional medical records across the full patient lifecycle (birth through death). The output is structurally valid FHIR / C-CDA / CSV that downstream health IT systems consume without exposing any real patient data.
Source: github.com/synthetichealth/synthea (opens in new window).
Use this when:
For non-health-domain synthetic data use faker-synthetic-data. For the categories of PHI that Synthea avoids exposing see pii-categories-reference (HIPAA Safe Harbor 18 identifiers).
When to use
How to use
Authoring
Install + build
Per github.com/synthetichealth/synthea (opens in new window):
git clone https://github.com/synthetichealth/synthea.git
cd synthea
./gradlew build check testRequires Java JDK 17 or newer (LTS versions recommended per the README).
Generate a population
Basic invocation:
./run_syntheaWith explicit population size and state:
./run_synthea -p 1000 MassachusettsPer the README: -p sets population size; the trailing argument sets the US state (locale-aware demographics and provider networks).
Common run flags
| Flag | Purpose |
|---|---|
-p <n> | Population size |
-s <seed> | Random seed (deterministic output) |
-cs <seed> | Clinician seed |
-r <date> | Reference date (YYYYMMDD) |
-e <date> | End date |
-g <M|F> | Filter by gender |
-a <minAge>-<maxAge> | Age range |
-c <config.properties> | Override configuration file |
Output formats
Per the README the system emits:
Output destination: ./output/fhir/, ./output/csv/, etc.
Configure formats in src/main/resources/synthea.properties:
exporter.fhir.export = true
exporter.fhir_stu3.export = false
exporter.ccda.export = false
exporter.csv.export = trueRunning
Pre-generated population
For quick starts MITRE distributes pre-generated SyntheaMass populations (1M patient Massachusetts simulation, etc.) on the project site - search for "Synthea downloadable populations" if you don't need to regenerate.
Disease modules
Synthea uses a Modular Rule System (per README) where each disease / condition is a JSON-defined state machine in src/main/resources/modules/. Examples include diabetes, hypertension, COPD, opioid addiction, COVID-19, sepsis, and dozens more. The module drives the patient's clinical journey probabilistically.
To add a custom module, drop a JSON spec into the modules directory; the engine picks it up on next run.
Loading into a FHIR server
# After ./run_synthea generates output/fhir/*.json
for f in output/fhir/*.json; do
curl -X POST -H "Content-Type: application/fhir+json" \
-d @"$f" http://localhost:8080/fhir/
doneFor bulk-FHIR ingestion, use the output/fhir/*.ndjson files with your server's bulk-data endpoint.
Parsing results
CSV outputs have predictable schemas:
output/csv/
patients.csv - patient_id, birthdate, deathdate, ssn, drivers, ...
encounters.csv - encounter_id, patient, organization, ...
conditions.csv - start, stop, patient, encounter, code, description
medications.csv - start, stop, patient, code, description, ...
observations.csv - date, patient, encounter, code, value, units
procedures.csv
immunizations.csv
allergies.csv
imaging_studies.csv
careplans.csv
claims.csvThe patients.csv ssn column contains fake SSNs in Synthea's reserved test range - they look real-formatted but don't correspond to issued SSAs. This is the intended HIPAA-safe replacement.
For FHIR output, parse with any standard FHIR client (HAPI FHIR Java, fhir.resources for Python, etc.).
CI integration
For health IT projects, regenerate Synthea data on every PR with a pinned seed so the dataset is reproducible. The full GitHub Actions job (build, generate, load into a local HAPI FHIR server, run integration tests) plus the pin-to-a-tag note is in references/ci-integration.md.
Worked example
Generate 100 diabetic patients aged 40-75 in Massachusetts, then verify the output before loading it into a test FHIR server:
./run_synthea -p 100 -s 42 -a 40-75 Massachusetts \
-m diabetes-m <module> filters to runs that include the named module; -s 42 pins the seed so the same 100 patients regenerate every time. Output appears in ./output/ (fhir/, csv/, c-cda/ per synthea.properties).
Confirm the run: output/csv/conditions.csv should carry diabetes condition rows linked by patient to output/csv/patients.csv, and every patient's birthdate should place them in the 40-75 age band. Once verified, POST the output/fhir/*.json bundles into the test FHIR server as shown under "Loading into a FHIR server".
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Using a real-patient seed file then claiming "synthetic" | Real PHI inadvertently embedded; HIPAA exposure | Always start from Synthea defaults or audited synthetic seed |
| Running without a pinned seed in CI | Output drifts across runs; test fixtures unstable | -s <seed> per CI run; pin Synthea version |
Faking demographics with faker-synthetic-data for a health context | Faker generates uncorrelated values; ICD codes, medications, encounters don't link | Use Synthea for any health-domain dataset |
| Loading Synthea output into a "real" FHIR server without isolation | If a misconfigured environment crosses into production, fake patients land in real EHR | Strict env separation; namespace Synthea patient IDs (prefix with synth-) |
| Treating Synthea SSNs as truly safe in all jurisdictions | Synthea uses reserved SSN ranges but format is still HIPAA-flagged | Pair with presidio-pii-detection on logs to confirm no SSN leakage |
| Custom module without validation | Malformed module silently runs (or doesn't); fixtures look right but cover nothing | Validate JSON modules against Synthea's schema before running large populations |
| Single-state generation for a national rollout test | Demographic skew (e.g., MA is not Texas) | Generate per state and merge |
Limitations
References
Synthea CI integration
View source (opens in new window)Synthea CI integration
Referenced from SKILL.md (opens in new window). For health IT projects, regenerate Synthea data on every PR with a pinned seed so the dataset is reproducible:
jobs:
fhir-integration-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-java@v5
with: { java-version: '17', distribution: 'temurin' }
- run: git clone https://github.com/synthetichealth/synthea.git
- run: cd synthea && ./gradlew build -x test
- run: cd synthea && ./run_synthea -p 50 -s 2026 Massachusetts
- run: |
# Load Synthea output into local FHIR server
docker-compose up -d hapi-fhir
for f in synthea/output/fhir/*.json; do
curl -sS -X POST -H "Content-Type: application/fhir+json" \
--data-binary @"$f" http://localhost:8080/fhir/
done
- run: pytest tests/integration/For repeatable tests, pin Synthea to a tag (git checkout v3.x.x) since modules evolve.
Related skills
data-masking-techniques-reference
Pure-reference catalog of data-masking techniques and de-identification privacy models. Enumerates the seven canonical masking operators (substitution, shuffling, number/date variance, encryption, hashing, nulling, masking-out / character-scrambling) plus tokenisation, redaction, format-preserving encryption, and Microsoft Presidio's six built-in operators. Distinguishes reversible techniques (pseudonymisation candidates per GDPR Art. 4(5)) from irreversible techniques (anonymisation candidates), and maps them to NIST SP 800-188 privacy models - k-anonymity, l-diversity, t-closeness, differential privacy (deep model definitions in references/). Cites ISO/IEC 20889:2018 for the standard taxonomy. Use to pick the right masking operator per field type and risk level.
faker-synthetic-data
Substitutes realistic replacement values for PII that a masking or de-identification step removed, nulled, or redacted, so a non-production dataset stays usable. Covers building an injective substitution map that keeps a shared identifier consistent everywhere it appears so joins survive; choosing deterministic (seeded) over random substitution, and the re-identification risk a shared or committed seed reintroduces, since a generator seed is a reproducibility control and not a cryptographic key; preserving field shape where a downstream system validates it, including check-digit values such as payment-card and national-ID numbers plus phone and postal formats; and why a value that merely looks realistic is not yet safe, leaving a residual re-identification measurement over the remaining quasi-identifiers. Use when a masking pipeline has nulled or dropped PII columns and the dataset now needs replacement values that keep cross-table joins intact.
k-anonymity-verifier
Verifies that a masked dataset satisfies k-anonymity, l-diversity, and t-closeness by computing equivalence classes over chosen quasi-identifiers and reporting re-identification risk. Covers quasi-identifier selection heuristics, threshold guidance, pycanon API (k_anonymity / l_diversity / t_closeness / report), ARX Java API and GUI workflow, SmartNoise for differential-privacy comparison, and CI-gate integration. Distinct from data-masking-techniques-reference (which catalogs masking operators but defers k-anonymity measurement to dedicated tooling) and from presidio-pii-detection (which detects PII spans but offers no equivalence-class analysis). Use when you need to confirm whether a masked dataset meets a stated k, l, or t threshold before promoting it to a non-production environment.
pii-categories-reference
Pure-reference catalog of personally identifiable information (PII) categories across GDPR, CCPA/CPRA, NIST SP 800-122, and HIPAA. Defines what counts as personal data under each regime, enumerates the explicit identifiers each regulator lists (GDPR Art. 4(1) and Art. 9 special categories; CPRA sensitive personal information; NIST direct-identifier vs linkable distinction; HIPAA Safe Harbor 18 identifiers), and maps overlapping fields across jurisdictions so a masking pipeline knows which regulator's rules apply. Use as the authoritative source when authoring or reviewing masking rules, classifying a dataset's risk level, or scoping which fields a PII detector must catch.
pii-masking-pipeline-builder
Build-an-X workflow that produces a PII masking pipeline spec from a source-data inventory. Walks the author through (1) classifying each field against pii-categories-reference, (2) picking a masking operator from data-masking-techniques-reference, (3) deciding pseudonymisation (reversible, in GDPR scope) vs anonymisation (irreversible, out of scope), (4) ordering the pipeline (detect → operator → audit), and (5) emitting a deployable config for Presidio + Faker + Synthea wrappers. Output is a YAML pipeline spec plus a per-field rationale table. Use after classifying a dataset's PII risk; this is the workflow that translates classification into runnable masking config.
presidio-pii-detection
Author and run Microsoft Presidio PII detection - wraps presidio-analyzer (PII detector) + presidio-anonymizer (replace/redact/mask/hash/encrypt operators) for scanning datasets, log streams, and free-text fields. Covers AnalyzerEngine + AnonymizerEngine setup, built-in recognizers (PERSON, EMAIL_ADDRESS, CREDIT_CARD, US_SSN, IBAN_CODE, country-specific IDs across US/UK/Spain/Italy/Poland/Singapore/Australia/India and more), custom PatternRecognizer authoring, score thresholds, and CI gating. Use when scanning *existing* data for PII (vs synthesising fresh fixtures with synthetic-pii-generator).
test-data-governance-reference
Pure-reference catalog of test-data lifecycle governance: retention schedules for test datasets, cross-environment data-sharing agreements, deletion of test data containing real PII, refresh cadence, access controls, and the legal basis for each policy under GDPR Art. 5 storage limitation and NIST SP 800-122. Use when defining a data-steward role for test environments, authoring a retention policy for a test database, scoping a data-sharing agreement before promoting a dataset from production to staging, or determining the deletion timeline for any test fixture that contains live personal data.