Terminologies in FHIR: Without SNOMED/LOINC, It Gets Expensive — How to Keep Code Systems Under Control
If you move from documents (CDA/PDF) toward FHIR resources, you’ll notice quickly: the real complexity isn’t the JSON — it’s the semantics. An Observation is only interoperable when it’s clear what was measured, in which unit, with which code, and how that code must be interpreted.
This is exactly where it gets expensive if terminologies are treated as “we’ll do it later”.
Why “FHIR without terminologies” becomes expensive
1) The cost trap: “local codes everywhere”
Without shared code systems, every interface becomes a custom translation project: Lab A ↔ HIS B ↔ Hospital C ↔ Research D. Each system builds its own mappings — which then need maintenance, testing and versioning. The effort doesn’t scale linearly. It explodes.
2) Interoperability becomes an illusion
FHIR standardizes transport and structure. Meaning comes from terminologies. If everyone encodes “HbA1c” differently, the result is: technically exchangeable, clinically not comparable.
3) Analytics, CDS, and secondary use fail first
- Quality indicators, registries, research, AI/ML, Clinical Decision Support: all depend on stable codes.
- Without solid terminology governance, projects become “data cleansing as a permanent state”.
SNOMED CT and LOINC: Why these two in particular?
LOINC: Lab & clinical observations (and more)
LOINC is the de-facto standard for lab and observation identifiers and is maintained by Regenstrief. LOINC is generally free to use, but subject to terms of use. (Regenstrief Institute)
SNOMED CT: clinical concepts (diagnoses, findings, procedures, body sites …)
SNOMED CT is the comprehensive clinical terminology. For Germany: membership since 01/01/2021; national release infrastructure via BfArM; affiliate process via MLDS; plus a German National Edition/Extension (translations, subsets, mappings). (BfArM)
LOINC answers: “Which test / observation type?”
SNOMED CT answers: “Which clinical concept?”
FHIR terminology building blocks: CodeSystem, ValueSet, ConceptMap — and why this isn’t optional
CodeSystem
“Where does the code come from?” — e.g., LOINC, SNOMED CT, UCUM, ICD, local systems.
ValueSet
“Which codes are allowed / preferred for this purpose?” ValueSets are the control lever for interoperability: they define the allowed slice of a code system.
ConceptMap
“How do I translate from system A to system B?” If local codes must remain, ConceptMap is your insurance policy — but only if it’s versioned and maintained.
ValueSet
$expand, ValueSet $validate-code, CodeSystem $lookup, ConceptMap $translate
The “expensive” part: governance, not technology
Typically ends in mapping backlogs, inconsistent translations and clinically ambiguous data.
Better: use local codes only where there truly is no standard — and define the translation strategy immediately.
Without ValueSets you can’t test conformance. Everything is “somehow compatible” — until production breaks.
Excel is fine as a working tool — but not as an operating model. Mappings need ownership, versioning, tests, approvals and distribution.
A manageable target model: 3 layers that work together
Layer 1: canonical standards (wherever possible)
- Observation.code → LOINC (labs/observations)
- Condition / Procedure / BodySite / ClinicalFinding → SNOMED CT (depending on use case)
- Units → UCUM (practically the default in FHIR)
Layer 2: ValueSet governance (the interoperability lever)
- For every relevant FHIR element binding, define a clear ValueSet: “must / should / may” (binding strength)
- Rule: nothing goes to production without validate-code against the ValueSet, at least in tests/CI.
Layer 3: translations & local reality (ConceptMap)
If local codes remain (and yes, this happens), then:
- Local codes must be defined cleanly in their own CodeSystem
- They require a robust ConceptMap to standard terminologies
- Every translation is versioned and testable (regression!)
Terminology service: without a central instance, you’ll get wild growth
In larger environments, a terminology service is practically mandatory:
- ValueSet expansion (
$expand) - Code validation (
$validate-code) - Lookup/display (
$lookup) - Mapping/translation (
$translate) - Subsumption/hierarchy queries (especially for SNOMED CT)
If every system expands ValueSets and maintains codes on its own, differences are guaranteed. Centralization makes things stable.
Practical approach: what “manageable” looks like in reality
Step 1: define your code strategy per resource
Example “lab”:
- Observation.code: LOINC
- Observation.value[x]: with UCUM
- Interpretation: from a defined ValueSet
- Method/BodySite: if needed, SNOMED CT
// Example box: lab Observation (excerpt)
Observation.code.coding.system = "http://loinc.org"
Observation.code.coding.code = "4548-4" // HbA1c (example)
Observation.valueQuantity.value = 6.8
Observation.valueQuantity.system= "http://unitsofmeasure.org"
Observation.valueQuantity.code = "%"
Step 2: establish a ValueSet minimum
Start small — but make it binding:
- “Top 50” lab parameters
- “Top 20” vital signs
- “Top 30” document types / questionnaire items (depending on scope)
Step 3: clarify licensing & distribution (SNOMED CT)
- Affiliate license via MLDS (process described by BfArM)
- Consider National Edition/Extension (translations, subsets, mappings)
Step 4: treat mappings like a product
- Owner per mapping domain (labs, diagnoses, documents …)
- Review process (clinical + technical)
- Versioning (release notes!)
- Automated tests: mapping exists? target code valid in ValueSet? no dead references?
Step 5: integrate tooling into CI/CD
- FHIR validator against profiles
- Terminology validation against ValueSets (at least pre-deploy)
- Regression testing for ValueSet/CodeSystem updates
Common pitfalls (and how to avoid them elegantly)
Display is UI help — not semantic truth. Truth is code + system + version.
Especially with SNOMED CT (and LOINC releases), versions matter. Without version discipline, interpretation becomes unstable.
SNOMED CT supports complex expressions. Powerful — but only manageable with rules and tooling. Otherwise: creative coding without comparability.
Different servers/versions/cache states lead to differences. Central expansion or tightly controlled releases prevent surprises.
Checklist for vendors and hospitals
If you take only 10 points, take these:
- ✓Define the target code system per domain (LOINC/SNOMED/…)
- ✓Build ValueSets as binding contracts (not documentation)
- ✓Enforce $validate-code in tests/CI
- ✓Use local codes only with a clear translation strategy (ConceptMap)
- ✓Treat mappings as a versioned product, not an Excel sheet
- ✓Clarify SNOMED licensing/MLDS early
- ✓Plan terminology updates as a release process (not “on the side”)
- ✓Centralize terminology functions (terminology service) where possible
- ✓Document TerminologyCapabilities (what can your server do?)
- ✓Make metadata quality measurable (coverage, validation rate, mapping coverage)
Conclusion: terminologies are the price of interoperability — and also the biggest lever
FHIR makes exchange modern and scalable. But without terminologies, you only get syntactic interoperability: data looks the same but doesn’t mean the same.
If you save on terminologies, you’ll pay later — in mapping debt, data cleansing, and loss of trust.