Overview
Extensions are part of the FHIR information model
FHIR keeps the base resource definitions manageable by allowing additional requirements to be represented as extensions. An application should not reject a resource merely because an extension is present, although the content of a particular extension can still make the resource unacceptable for a profile or workflow.[1]
{
"resourceType": "Patient",
"id": "patient-1",
"extension": [{
"url": "https://example.test/fhir/StructureDefinition/preferred-contact-time",
"valueTime": "14:30:00"
}]
}
This synthetic example adds a preferred contact time that is not represented by a normal Patient element. The extension is not an untyped JSON object. Its url identifies the definition and its valueTime states both the value and the FHIR data type.
Do not decide whether an extension matters from its position or URL text alone. Resolve or otherwise obtain the applicable StructureDefinition, then check its context, value type, constraints and modifier status.
Extension structure
url identifies the definition; value[x] carries the typed value
In FHIR R4, Extension.url is mandatory. Except for child extensions inside a complex extension, it is an absolute canonical URL for the StructureDefinition that defines the extension. That definition supplies the meaning; changing the URL means the instance is claiming a different definition.[1]
| Part | Purpose | Check |
|---|---|---|
| url | Identifies the extension definition and therefore its meaning. | Compare the complete canonical URL, including scheme, path and case. |
| value[x] | Holds one typed value, such as valueBoolean, valueCode or valueReference. | Check that the selected type is allowed by the extension definition. |
| extension | Holds child extensions when the extension is complex. | Check child URLs and cardinalities against the parent definition. |
| id | Provides an optional internal element identifier. | Do not confuse it with the extension's canonical URL. |
The literal property is never named value[x] in JSON or XML. The [x] notation means the element name includes the chosen FHIR type: valueString, valueCoding, valueDateTime and so on. A generic parser that searches only for a property called value will miss these values.
An extension has a value or child extensions, not both
The R4 extension invariant requires either a value[x] element or nested extension elements, but not both. A complex extension groups several named parts as children:
{
"url": "https://example.test/fhir/StructureDefinition/contact-window",
"extension": [
{ "url": "start", "valueTime": "09:00:00" },
{ "url": "end", "valueTime": "17:00:00" }
]
}
The short child URLs are interpreted within the parent extension definition. They are not independent global extension identities. Flattening this object to a single string loses its child names and types.
Location and context
An extension can qualify a resource, element or primitive value
Extensions can appear at many levels. A root resource extension can apply to the resource as a whole; an extension on a complex element applies at that element; and primitive values have a separate JSON representation for metadata and extensions.[2]
Primitive extensions use the underscore property in JSON
{
"resourceType": "Patient",
"birthDate": "1980-04-12",
"_birthDate": {
"extension": [{
"url": "https://example.test/fhir/StructureDefinition/date-source",
"valueCode": "reported"
}]
}
}
The extension belongs to the primitive birthDate element, so its JSON metadata appears under _birthDate. Code that copies only birthDate can silently discard its extension. The underscore object is also used when a primitive has an extension but no primitive value.
Array primitives require particular care because the value array and underscore metadata array are positionally aligned. Removing empty placeholders or independently sorting one array can attach metadata to the wrong value.[2]
Context still applies. A published extension definition declares where it may be used. A valid extension object placed on an element outside that context can still fail profile validation.
Modifier extensions
modifierExtension can change how the containing data is interpreted
An extension must be represented as modifierExtension when it is not safe for a consumer to ignore it. A modifier can negate or otherwise qualify the meaning of the element that contains it or that element's descendants. Its effect is local to that containing element; it cannot redefine unrelated parts of the resource.[1]
{
"resourceType": "MedicationRequest",
"id": "request-1",
"status": "active",
"intent": "order",
"modifierExtension": [{
"url": "https://example.test/fhir/StructureDefinition/do-not-administer",
"valueBoolean": true
}],
"medicationCodeableConcept": {
"text": "Synthetic medication"
},
"subject": {
"reference": "Patient/patient-1"
}
}
The example URL is synthetic and does not define a real clinical rule. It illustrates why a consumer cannot process the medication instruction from the ordinary fields while silently dropping the modifier. The definition of an actual modifier extension must explain its effect.
Unknown extension and unknown modifierExtension are different cases
| Encountered content | General R4 handling |
|---|---|
Known ordinary extension | Process it according to its definition and the receiving workflow. |
Unknown ordinary extension | Do not treat the resource as invalid merely for containing it. Ignore it for processing when appropriate and retain it whenever possible. |
Known modifierExtension | Apply its defined effect when processing the containing data. |
Unknown modifierExtension | Do not process the affected data as though the modifier were absent. Reject it, warn appropriately, restrict use to safe rendering, or obtain human review. |
FHIR R4 requires implementations processing resource data to check for modifier extensions wherever they can appear. A system that only transports the complete resource unchanged is treated differently from one that copies, filters, maps, stores for downstream use or converts the data into another format.[1]
Validation
Valid JSON does not prove that an extension is conformant
A JSON parser can confirm syntax but cannot decide whether an extension URL is known, whether its value type is permitted or whether it appears in the correct context. Those checks require the extension's StructureDefinition and any profiles or implementation guides claimed by the resource.
For each extension, a profile-aware validator can check:
- whether the canonical URL resolves to or matches an available extension definition;
- whether the extension is ordinary or modifying;
- whether the chosen
value[x]type and cardinality are allowed; - whether a complex extension contains the required child URLs;
- whether the extension is permitted at the element where it appears; and
- whether profile slicing, terminology bindings and invariants are satisfied.
A receiver can also impose narrower requirements than base FHIR R4. Check the exact implementation-guide version and package used by both systems before concluding that the payload or validator is wrong.
Failure patterns
Common FHIR extension processing failures
| Symptom | Likely cause | What to compare |
|---|---|---|
| Extension is present but the mapped value is empty | The parser searched for value instead of the actual typed property. | Inspect all value* properties and the permitted type in the definition. |
| Receiver reports an unknown extension | The canonical URL is misspelled, locally rewritten or absent from the validator's packages. | Compare the complete URL and implementation-guide package versions. |
| Validator reports the extension at the wrong path | The extension definition does not allow that resource or element context. | Instance path against the definition's context expressions. |
| Complex extension fails its invariant | It contains both a direct value and child extensions, or required children are missing. | Parent value[x], child URLs and cardinalities. |
| Primitive metadata disappears after transformation | The underscore property was not copied with the primitive value. | Original and output field/_field pairs. |
| Downstream meaning changes after mapping | An unknown modifierExtension was dropped or ignored. | Every modifier location on the resource and processed backbone elements. |
Troubleshooting sequence
Inspect the instance before changing the mapping
- Preserve the original resource. Work from an unchanged synthetic reproduction so transformations do not hide the failure.
- Locate every extension. Search for
extension,modifierExtensionand underscore primitive metadata objects. - Record the exact path and URL. Include the containing resource or element path, not only the extension object.
- Open the matching definition. Confirm its canonical URL, modifier status, allowed context, cardinality, value type and child slices.
- Check the effective profile set. Use
meta.profile, the endpoint contract and the correct implementation-guide package version. - Trace preservation. Compare the resource before and after parsing, mapping, storage and serialization, including primitive underscore properties.
- Handle modifiers explicitly. Stop affected processing when the modifier's meaning is not understood; do not merely log and continue.
- Validate the final output. Run a profile-aware validator and confirm the destination interprets the extension as intended.
The FHIR JSON Formatter & Resource Viewer can expose the exact JSON paths and typed values. The FHIR Resource Diff can then show whether an extension, child part or underscore metadata object changed during a transformation. These tools help inspect the payload; they are not substitutes for a complete profile validator.
Implementation checklist
Checks for a safer extension pipeline
- Compare extension identity using the complete canonical URL.
- Read the actual typed
value[x]property, not a guessed generic value. - Support nested complex extensions without flattening away child URLs.
- Preserve primitive underscore metadata and array alignment.
- Retain unknown ordinary extensions whenever the workflow permits.
- Search for and handle
modifierExtensionat every processed level. - Validate against the correct profiles and implementation-guide package versions.
- Use synthetic payloads in tickets, tests and shared logs.
Primary sources
FHIR R4 references
- HL7 FHIR R4: Extensibility — extension structure, canonical URLs, value rules, modifier extensions and processing obligations.
- HL7 FHIR R4: JSON representation — typed values and primitive-value metadata representation.
- HL7 FHIR R4: Conformance rules for modifier elements — why modifier elements cannot be safely ignored.