Lesson 36 of 51 · The FHIR Model
Data Types and Extensions
What an element holds
Earlier lessons showed that a FHIR resource is built from elements — named
fields such as a Patient’s name or an Observation’s value. Every element has a
data type that defines what it can contain. FHIR’s data types come in two
families 1.
Primitive types carry a single, atomic value: string, boolean, integer,
decimal, uri, code, dateTime, and instant, among others. A code is a
constrained string limited to a fixed set of allowed values; dateTime permits
varying precision (a year alone, or a full timestamp), while instant requires a
precise moment down to the second with a timezone. Each primitive has rules for its
allowed format, which lets software validate a value without understanding its
meaning.
Complex types are built from other elements — they are small, reusable structures rather than single values. Because the same shapes recur across many resource types, FHIR defines them once and reuses them everywhere.
The high-value complex types
A handful of complex types appear constantly 1:
- HumanName — the parts of a name (
family,given,prefix) plus ause(official, nickname) and atextrendering. - Address —
line,city,state,postalCode,country, with auseandtype. - Identifier — a business identifier such as a medical record number,
qualified by the
systemthat issues it so the same number from two organizations cannot be confused. - Period — a start and end time, used wherever something is valid for a span.
- Quantity — a measured
valuewith aunit, plus a codedsystemandcodefor the unit so “mg” is machine-comparable rather than free text. - Reference — a pointer from one resource to another, covered in the previous lesson; it too is simply a data type.
The most important pair is Coding and CodeableConcept, which is where the terminologies course connects directly to the resource model.
Coding and CodeableConcept
The terminologies course introduced the code + system + display triplet: a
coded value is never just a code, because the same code means different things in
different code systems. FHIR encodes that triplet as the Coding type — a single
coded value with a system (the URI naming the code system), a code, and a
display (the human-readable label) 1:
{
"system": "http://loinc.org",
"code": "789-8",
"display": "Erythrocytes [#/volume] in Blood by Automated count"
}
A CodeableConcept wraps one or more Codings plus an optional free-text
description. Multiple Codings let the same concept be expressed in several code
systems at once (a local code and a standard code side by side), and the text
preserves the original wording even when no code captures it perfectly
1:
{
"coding": [
{ "system": "http://loinc.org", "code": "789-8", "display": "RBC count" }
],
"text": "Red blood cell count"
}
This is the direct successor to HL7 v2’s CWE (“coded with exceptions”) data type, which paired a code with its coding system and display text and allowed a free-text fallback. FHIR keeps the same idea — codes are meaningful only alongside the system that defines them — but expresses systems as resolvable URIs and lets a CodeableConcept hold several codings together 2.
Extensions: governed extensibility
No fixed specification can anticipate every local data need, so FHIR builds an
escape valve into the model itself: every element in every resource may carry
extension entries 1. An extension has a url that
defines its meaning — and points to its formal definition — and a single value,
recorded in a value[x] element whose name encodes its type (valueString,
valueCodeableConcept, valueDateTime, and so on):
{
"extension": [
{
"url": "http://example.org/fhir/StructureDefinition/birthPlace",
"valueString": "Wellington, NZ"
}
]
}
The design intent is controlled, governed extensibility. Anyone can attach extra data without forking the specification, because an extension’s meaning lives at a resolvable URL that anyone can look up — the data stays self-describing and discoverable 1.
A special variant is modifierExtension. An ordinary extension adds information that a system may safely ignore if it does not recognize it. A modifierExtension, by contrast, changes how the containing element is understood — for example, marking a record as entered in error — and so it must not be ignored. A system that encounters a modifierExtension it does not understand should refuse to process the element rather than silently misinterpret it 1.
This is a more disciplined version of a familiar idea. HL7 v2 met the same need with Z-segments: locally agreed custom segments that worked between two trading partners but were undocumented in the standard and opaque to anyone else. FHIR extensions serve the identical purpose — adding local data — but every extension is URL-defined and discoverable rather than privately negotiated, so the meaning travels with the data instead of living only in a partner agreement 2.
References
- HL7 FHIR Release 4 (R4), v4.0.1. HL7 International. 2019. verified Cited at: datatypes.html; extensibility.html.
- Tim Benson, Grahame Grieve. Principles of Health Interoperability: FHIR, HL7 and SNOMED CT. 4th ed. Springer. 2021. verified