๐Ÿท๏ธ Terminology & validation

Every coded field โ€” a diagnosis, a lab, a medication โ€” quietly drags you into running a terminology server. bonfire validates codes on write, powers your pickers with code-search, and ships value sets bundled and version-pinned. So "store a diagnosis" stops being a project.

why it's different

FHIR validates the shape. It doesn't know the code is real.

FHIR will happily tell you a CodeableConcept is well-formed. It won't tell you the code actually exists in LOINC, or that the diagnosis you stored is a real ICD-10 code, or that the RxNorm identifier means the drug you think it means. That answer lives in a terminology server โ€” $validate-code and $expand over LOINC, SNOMED CT, RxNorm, ICD-10 โ€” and standing one up is its own infrastructure project. bonfire folds it into the write path.

Validate on write

A coded field is checked against its code system before it commits. Garbage codes fail at the door, not in a downstream report six weeks later.

Search for pickers

Type-ahead code search powers your dropdowns. Clinicians pick from real codes by name โ€” they never memorize a numeric identifier.

Bundled & version-pinned

Value sets ship with the package, pinned to a known release. No live call to an external server on the hot path, no silent drift between deploys.

Structure and semantics

FHIR checks the shape; bonfire checks the meaning. Both run, so a stored diagnosis is well-formed and a code that exists.

Validate a code in one call โ€” on the write path

You don't stand up a $validate-code endpoint, manage its uptime, or decide what to do when it times out mid-write. You ask bonfire whether a code is valid in its system, and the answer comes back with the display string the code resolves to.

โœ“ Checked against the pinned value set โ€” deterministic, no network race on the commit path.
โœ“ Returns the canonical display, so your UI shows the official label, not whatever was typed.
โœ“ Same gate for LOINC, SNOMED CT, RxNorm, and ICD-10 โ€” one call, four code systems.

$validate-code, without a terminology server to operate.

validate.ts
// is this a real LOINC code? what does it mean?
const r = await clinical.terminology.validate(
  "LOINC",
  "4548-4"            // Hemoglobin A1c
)

r.valid    // true
r.display  // "Hemoglobin A1c/Hemoglobin.total in Blood"
r.system   // "http://loinc.org"
r.version  // pinned release, not "whatever's live today"

// a code that doesn't exist fails before it commits
const bad = await clinical.terminology.validate(
  "LOINC", "0000-0"
)
bad.valid  // false โ†’ the write is refused
the SNOMED footnote everyone gets wrong

SNOMED CT is free for US use โ€” under the NLM UMLS license

Teams routinely assume SNOMED CT means a licensing bill. For use within the United States, it's free: the U.S. is a SNOMED International member, and the U.S. Edition is distributed at no cost through the National Library of Medicine, accessed under a (free) UMLS Metathesaurus License. bonfire bundles the value sets so you build on that fact instead of rediscovering it. Outside the U.S., SNOMED licensing follows your country's Member or Affiliate terms โ€” check yours.

The assumption

"SNOMED is a paid vocabulary, so we'll just store free-text diagnoses and clean it up later." The cleanup never happens, and your data is uncoded.

The reality

SNOMED CT US Edition is free via the NLM UMLS license. Coded from the start costs you nothing โ€” and bonfire ships the value sets so it's the default path, not the heroic one.

"FHIR" and the names of code systems are descriptive references to their respective standards and owners (HL7ยฎ, SNOMED International, Regenstrief/LOINC, NLM/RxNorm, WHO/CDC ICD-10). Always confirm current license terms with the source before you ship โ€” terms change, and your jurisdiction matters.

Code search is the picker

A clinician types "a1c" and gets the matching coded concepts back, ranked, ready to drop into a dropdown. The picker is just a thin call over the same bundled value sets โ€” you don't scrape a CSV, host a search index, or hand-maintain a list of "common codes."

  • โœ“ Search by name or partial code โ€” returns code, display, and system together.
  • โœ“ Backed by the pinned value set, so results match what validate will accept.
  • โœ“ Scope a search to the value set a given field allows, so pickers only offer valid choices.

The result of a search is, by construction, a code that will pass validation โ€” the picker and the gate read the same source.

LabPicker.tsx
// autocomplete a lab picker from real LOINC
const options = await clinical.terminology.search(
  "a1c",
  { system: "LOINC", limit: 8 }
)

// [{ code, display, system }, โ€ฆ]
options.map(o => ({
  value: o.code,        // "4548-4"
  label: o.display,     // "Hemoglobin A1cโ€ฆ"
  system: o.system      // "http://loinc.org"
}))

// whatever the user picks already validates โ€”
// picker and write-gate share one value set
how it stays honest

Bundled and version-pinned, so codes don't drift under you

Calling a live external terminology server on every write means your validation result depends on someone else's uptime and someone else's last release. bonfire bundles value sets into the package and pins them to a version. Your validation is deterministic across environments, your CI doesn't fail because a remote server hiccuped, and a vocabulary update is a deliberate, reviewable bump โ€” not a surprise.

1

Value sets ship in the package

The code systems you need come bundled and pinned. No terminology server to provision, secure under a BAA, and keep alive.

2

Validation reads the pinned set

Every validate and search resolves against that exact release โ€” same answer in dev, CI, and prod.

3

Updates are a reviewed bump

A new vocabulary release is an explicit version change you can diff, test, and roll out โ€” not a silent shift in what "valid" means.

honest scope

Built-in terminology โ€” not a full terminology service

bonfireDB is pre-launch / early access. The goal is to make the common coded fields outpatient apps reach for first a non-event: validate them, search them, store them coded. It is deliberately not a complete terminology service. Full SNOMED CT subsumption, every value set, hierarchy reasoning, and arbitrary $expand filters are a journey โ€” and where you need that depth, a dedicated terminology server still earns the job.

What's designed in

  • Validate-on-write across LOINC, SNOMED CT (US Edition), RxNorm, and ICD-10
  • Code-search / autocomplete for pickers, over the same pinned sets
  • Bundled, version-pinned value sets โ€” deterministic, no live dependency on the hot path
  • Canonical display resolution, so the UI shows the official label

What it isn't (yet)

  • A complete terminology server with the full release of every code system
  • SNOMED subsumption / hierarchy reasoning and arbitrary $expand filters
  • Concept mapping between code systems ($translate / ConceptMap)
  • A managed authority for non-US SNOMED licensing or exotic value sets

Where bonfire stops, a dedicated terminology server begins โ€” and the FHIR R4 generated underneath means a code you stored here is a code you can hand to one cleanly.

side by side

What "store a diagnosis" actually costs

CapabilityFHIR data model aloneRoll your own terminology serverbonfireDB
Code exists in its systemShape only, no checkIf you build $validate-codeValidated on write
Picker / autocompleteYour job to buildStand up search yourselfBuilt-in code-search
Value-set hostingN/AYou operate the serverBundled, version-pinned
Deterministic across envsDepends on youTied to server uptime/releasePinned, reproducible
SNOMED CT (US) costN/AFree via NLM, you wire itFree set, bundled in
Full subsumption / $expand filtersNoYes, if you build itRoadmap โ€” scoped today

bonfireDB is early-stage; this page describes product design and positioning, not a benchmark. Code-system names are descriptive references to their owners' standards; licensing (including SNOMED CT's free US use via the NLM UMLS license) can change โ€” verify current terms with the source for your jurisdiction.

where this fits

Coded fields are the foundation the rest of the backend reads from

FHIR underneath

Validated codes flow straight into the FHIR R4 generated beneath your primitives โ€” clean to export.

Explore โ†’

App-native primitives

Assessments, observations, and diagnoses store coded by default โ€” no free-text-now, fix-later.

Explore โ†’

Authorization & audit

Every coded write runs the same access gate and emits an AuditEvent, like every other write.

Explore โ†’

How it works

TypeScript + Postgres + pgvector, FHIR R4 underneath, no Redis โ€” see the full picture.

Explore โ†’

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

Validate codes on write, search them for your pickers, and store diagnoses coded from day one โ€” without standing up a terminology server. Start building on the open-source core.

FAQ

Frequently asked questions

How do I validate medical codes without running a terminology server?

bonfireDB folds $validate-code into the write path: a coded field is checked against its code system before it commits, so invalid codes are refused at the door. You don't stand up, secure, or keep alive a separate terminology server โ€” value sets ship bundled and version-pinned in the package. (bonfireDB is pre-launch / early access; this describes the design.)

Do I need a terminology server to validate LOINC, SNOMED CT, RxNorm, and ICD-10 codes?

Not for the common coded fields outpatient apps reach for first. bonfireDB is designed to validate-on-write and code-search across LOINC, SNOMED CT (US Edition), RxNorm, and ICD-10 with one call over bundled, pinned value sets. For full subsumption, every value set, or arbitrary $expand filters, a dedicated terminology server still earns the job.

Is SNOMED CT free to use in the United States?

Yes, for use within the US it's free. The US is a SNOMED International member and the US Edition is distributed at no cost through the National Library of Medicine under a free UMLS Metathesaurus License. Outside the US, licensing follows your country's Member or Affiliate terms โ€” verify current terms with the source for your jurisdiction.

How do I build a LOINC or ICD-10 code picker with autocomplete?

bonfireDB's code-search is the picker: a clinician types a partial name or code and gets ranked coded concepts back with code, display, and system, ready to drop into a dropdown. Because search and the write-gate read the same pinned value set, whatever the user picks already validates โ€” no scraped CSV or hand-maintained 'common codes' list.

Why bundle and version-pin value sets instead of calling a live terminology server?

Calling a live external server on every write makes validation depend on someone else's uptime and last release. bonfireDB bundles value sets and pins them to a known version, so validation is deterministic across dev, CI, and prod, and a vocabulary update is a deliberate, reviewable bump โ€” not silent drift.