How do you generate realistic clinical seed data for a healthcare app?
Run bonfire seed --patients 50 --profile us-core. It generates clinically coherent, longitudinal, comorbidity-correlated, profile-valid patients — HbA1c trends, medication escalation, imaging plus narrative notes — straight into your local Postgres-first instance, wired to the typed SDK. Your first realistic Patient is five minutes away, not a sprint.
Why does your healthcare app pass the sandbox and crash on the first real patient?
Because the data you tested on was nothing like a real chart. Open Epic gives you eight patients with sparse data. Synthea produces single-condition patients with no clinical depth. Your app demos green, then the first real patient arrives with three comorbidities, a four-year HbA1c trend, escalating insulin, an imaging report, and a wall of narrative notes — and the code that “worked” falls over. The fix is seed data that looks like the chart your app will actually meet on day one.
Clinically coherent
A patient with type 2 diabetes carries the labs, meds, and notes that diabetes actually drags along — not a random scatter of unrelated codes.
Longitudinal
Values move over time. An HbA1c reads as a trend across visits, with medication escalation that tracks the trajectory — not a single static row.
Comorbidity-correlated
Conditions cluster the way real ones do. Diabetes pulls in hypertension and hyperlipidemia; the chart hangs together instead of contradicting itself.
Profile-valid
--profile us-core means every generated resource validates against US Core — so your app is tested against the shapes it must ship.
Your first realistic Patient, in five minutes
One command stands up a roster of dense, coherent charts inside your local Postgres-first instance and wires them to the typed SDK. No external fetch, no fixture-by-hand, no “I’ll add real data later” that never happens. You read the seeded patients through the exact same client your app uses in production.
bonfire seed — dense charts on the first run, not the fortieth.
# 50 dense, US-Core-valid patients into local Postgres $ bonfire seed --patients 50 --profile us-core ✓ 50 patients generated (deterministic, seed=42) ✓ 1,284 Observations // HbA1c trends, vitals, lipids ✓ 612 MedicationRequests // escalation over time ✓ 188 DiagnosticReports + DocumentReferences ✓ all resources US-Core valid · queryable via SDK # read them back through the typed client $ bonfire query "Patient?_count=50"
What does a clinically-dense seed patient contain?
A dense patient is one whose chart tells a story that holds together over time. A seeded diabetic doesn’t get a lone diagnosis code — they get the trend, the treatment response, and the narrative a clinician would expect to read. Store a SOAP note as a FHIR DocumentReference, a lab as an Observation, a prescription as a MedicationRequest — and bonfire generates them correlated, not in isolation.
Sparse fixtures (Synthea / sandbox)
- One condition, a handful of codes, no temporal arc
- Single static lab value — no trend to chart or to break your math on
- Meds unrelated to the diagnosis; no escalation, no response
- No narrative notes — nothing for an AI scribe or summarizer to read
- Passes the demo, crashes on the first real patient
A bonfire-seeded patient
- Comorbidities that cluster realistically (diabetes + HTN + hyperlipidemia)
- HbA1c read as a four-year trend across dated encounters
- Medication escalation that tracks the lab trajectory over time
- Imaging (DiagnosticReport) plus narrative DocumentReference notes
- Every resource US-Core valid — the shape your app must ship against
Honest framing: bonfireDB is pre-launch / early access. This page describes the seed generator’s design, not a benchmark. Synthea is excellent for population-scale synthetic data; bonfire’s seed is tuned for a different job — a handful of deep charts that stress an outpatient app’s real read paths in minutes.
Per-test snapshot and reset
Seed once, then snapshot the database and reset between tests in milliseconds. Every test starts from the same dense roster, mutates freely, and rolls back — so your integration suite runs against realistic charts without leaking state from one test into the next.
- ✓ Snapshot captures the full seeded state; reset restores it without re-running generation.
- ✓ Each test gets an isolated, identical starting chart — no order-dependent flake.
- ✓ Fast enough to reset in a beforeEach, so suites stay both realistic and clean.
Realistic data and clean isolation are usually a tradeoff. Snapshot/reset gives you both.
import { seed, snapshot } from "bonfire-db/test" import { clinical } from "../client" // seed 50 dense charts once, snapshot the state const snap = await snapshot( await seed({ patients: 50, profile: "us-core" }) ) beforeEach(async () => { await snap.reset() // back to the dense roster, ms }) test("summarizes a multi-year HbA1c trend", async () => { const obs = await clinical.observations.list({ patient: "pt-001", code: "4548-4" // HbA1c }) expect(obs.length).toBeGreaterThan(4) // a real trend })
Three steps to a realistic Patient
Create the project
One command scaffolds the Postgres-first instance, pgvector, and the typed SDK — no Redis to provision. (CLI in early access.)
Seed dense charts
Generate 50 longitudinal, comorbidity-correlated, US-Core-valid patients straight into local Postgres.
bonfire seed --patients 50 --profile us-coreSnapshot & build
Snapshot the roster, reset between tests, and read it all through the same typed client your app ships with.
await snap.reset()Seed data options for a clinical app, compared
| Capability | Open Epic sandbox | Synthea | bonfire seed |
|---|---|---|---|
| Patients available | ~8, fixed | Population-scale | --patients N, your call |
| Clinical depth per chart | Sparse | Often single-condition | Dense, multi-condition |
| Longitudinal trends (e.g. HbA1c) | Minimal | Partial | Built in, dated |
| Comorbidity correlation | No | Limited | Correlated by design |
| Narrative notes for AI to read | Rare | No | DocumentReference notes |
| Profile validity (US Core) | Varies | Varies by config | --profile us-core |
| Wired to your typed SDK | External API | Files to import | Into local Postgres, queryable |
| Per-test snapshot / reset | No | No | Built in, ms |
bonfireDB is early-stage; this comparison describes product design and positioning, not a benchmark. Synthea (MITRE) is a strong open-source synthetic-data engine for population studies — a different job than a handful of deep charts for app testing. “FHIR” and “US Core” are descriptive references to HL7®'s standards; verify current implementation-guide versions before you ship.
Dense seed data is the on-ramp to the rest of the backend
AI scribe Fire Starter
Seed dense charts with narrative notes, then build the transcript-to-signed-note lifecycle on top of real-looking data.
Explore →How it works
TypeScript + Postgres + pgvector, FHIR R4 underneath, no Redis — see how seed, SDK, and store fit together.
Explore →Terminology & validation
Seeded codes are real codes — validated on write against LOINC, RxNorm, ICD-10 (bundled) and SNOMED CT (your UMLS license).
Explore →FHIR underneath
Every seeded patient is a clean FHIR R4 resource — export the roster the moment you need to.
Explore →You build the app. Bonfire is the clinical data layer underneath.
Generate 50 clinically-dense, longitudinal, US-Core-valid patients into local Postgres in five minutes — then snapshot and reset between tests. Get early access to the core (Apache-2.0 planned).
Frequently asked questions
How do I generate synthetic FHIR patients for local development?
Run bonfire seed --patients 50 --profile us-core. It is designed to generate longitudinal, comorbidity-correlated, US-Core-valid patients straight into your local Postgres instance, immediately queryable through the typed SDK. bonfireDB is in early access, so this describes the seed generator’s design.
What is the difference between bonfire seed and Synthea for clinical seed data?
As of mid-2026, Synthea (MITRE) is an excellent population-scale synthetic-data engine, often producing single-condition patients. bonfire’s seed is tuned for a different job: a handful of deep, multi-condition charts with longitudinal trends and narrative notes to stress an outpatient app’s real read paths in minutes.
How do I seed a local Postgres database with realistic clinical data?
One command generates dense charts into your local Postgres-first instance (Postgres + pgvector, no Redis, no cloud round-trip). Seeding is designed to be deterministic with a seed value, so the same command reproduces the same roster across machines and CI.
Does the seed data include longitudinal trends and narrative notes?
Yes, by design. A seeded diabetic patient is meant to carry an HbA1c trend across dated encounters, medication escalation that tracks that trajectory, imaging as a DiagnosticReport, and narrative notes as DocumentReferences for an AI scribe or summarizer to read.
How do I reset clinical test data between integration tests?
bonfire is designed to let you seed once, snapshot the full database state, then reset between tests in milliseconds. Each test starts from the same dense roster, mutates freely, and rolls back, so suites stay realistic and isolated without re-running generation.