App-native primitives ๐Ÿงฉ

Write clinical.notes.create() โ€” not POST /DocumentReference. bonfireDB gives you typed clinical functions that read like the workflow you're building, and generate FHIR R4 underneath when you need it.

Call the verb, not the resource

FHIR makes you translate every clinical action into a resource POST, a reference graph, and a write that assumes strangers. bonfireDB gives you the verb directly. A note is a note.

No reverse-engineering which resource a clinical note maps to. No hand-wiring the encounter reference. No guessing whether your write spawned a duplicate.

notes.ts
// One typed call. Returns a freshness object.
await clinical.notes.create({
  patientId,
  encounterId,
  text
})

Typed SDK, end to end

Every primitive is a real TypeScript method with real types โ€” arguments, returns, and the shape of what comes back. Your editor autocompletes the clinical model. A typo is a compile error, not a malformed Bundle you debug in production.

The same typed function is also an HTTP endpoint and an MCP tool. Write it once; it shows up everywhere.

read.ts
// Reactive, fresh on commit โ€” no manual refetch.
const notes = useClinicalQuery(
  api.notes.listByPatient,
  { patientId }
)

One assessment call, two FHIR resources

Record a PHQ-9 with one call. bonfireDB writes the QuestionnaireResponse and the scored Observation underneath โ€” correctly referenced, correctly coded โ€” so your app stays interoperable without you hand-assembling the resource graph.

Structured instruments, structured scores. Both generated, both queryable, both exportable.

assessments.ts
// -> QuestionnaireResponse + Observation
await clinical.assessments.record(
  "PHQ-9",
  { patientId, answers }
)

// Same pattern for any observation.
await clinical.observations.record({
  patientId,
  code: "tic-severity",
  value,
  effective
})

One model for app reads, audit, and interop

The same primitive that powers your list screen also produces the audit trail and the interop record. You don't maintain three representations of a clinical fact โ€” bonfireDB keeps app reads, the audit log, and the FHIR projection in sync from a single source of truth in Postgres.

No second database for "app state." No drift between what your UI shows and what you can export.

  • App reads stay fresh on commit โ€” no eventual-consistency lag.
  • Every read and write is captured for audit, automatically.
  • FHIR R4 generated underneath for export and interop.
export.ts
// Clean FHIR R4 Bundle on demand.
await clinical.fhir.export(patientId)

FHIR generated underneath

You build against verbs that match your product. bonfireDB keeps the corresponding FHIR R4 in sync underneath, so export and integration are there when you need them โ€” not bolted on later. Call clinical.fhir.export(patientId) and get a clean Bundle whenever you hand records to another system.

  • Write the workflow once; get FHIR for free.
  • Typed SDK method, HTTP endpoint, and MCP tool from a single definition.
  • No translating clinical actions into resource POSTs by hand.
  • No second app-state database and no sync hell.
  • Exportable R4 Bundles on demand โ€” interop without operating a FHIR server.

Related: FHIR underneath ๐Ÿ”ฅ ยท Always fresh โšก

freshness.ts
// Every write returns its freshness lifecycle.
{
  status: "committed",
  views: {
    notesByPatient: "fresh",
    timeline: "fresh"
  },
  indexes: {
    semanticSearch: "pending",
    agentContext: "pending"
  }
}

You build the app. Bonfire is the clinical data layer underneath.

Start with typed primitives that read like your product and generate FHIR R4 underneath.

FAQ

Frequently asked questions

What does an app backend that generates FHIR underneath (not a FHIR server) mean?

It means you write against typed clinical verbs that match your product โ€” like clinical.notes.create() โ€” instead of POSTing FHIR resources. bonfireDB owns a Postgres-first data plane and generates FHIR R4 underneath, so you build your app and get interop without hand-assembling resource graphs.

How is bonfireDB like Convex for healthcare?

bonfireDB is designed to give you Convex-style typed functions for clinical data: each primitive is a real TypeScript method that's also an HTTP endpoint and an MCP tool from a single definition, with reads that stay fresh on commit. The difference is it generates FHIR R4 underneath for export and interop. It's pre-launch / early access.

What are typed clinical primitives?

They're real TypeScript methods for clinical actions โ€” clinical.notes.create(), clinical.assessments.record("PHQ-9", ...), clinical.observations.record() โ€” with typed arguments and returns. Your editor autocompletes the clinical model, and a typo is a compile error instead of a malformed FHIR Bundle you debug in production.

Do I have to write FHIR resources by hand with bonfireDB?

No. You call the verb (a note is a note) and bonfireDB keeps the corresponding FHIR R4 in sync underneath. One assessment call, for example, is designed to write both the QuestionnaireResponse and the scored Observation โ€” correctly referenced and coded โ€” so you stay interoperable without wiring the resource graph yourself.

How do I export FHIR data from bonfireDB?

Call clinical.fhir.export(patientId) to get a clean FHIR R4 Bundle on demand. The same primitive that powers your app reads also produces the audit trail and the interop record from one source of truth in Postgres, so there's no second app-state database and no drift between your UI and what you export.