FHIR

FHIR profiles and extensions explained: how an implementation guide constrains a resource, and how to validate against it

A FHIR profile is a StructureDefinition that narrows a base resource: required elements, must-support, fixed codes, slicing, bindings, invariants. An extension adds what the base left out. How profiles are published, what meta.profile means, how validators check them, with a readable example of each.

by Published 6 min read

Short answer: the base FHIR resources are deliberately loose: almost everything is optional and most codes are only examples, so that one standard fits every country. A profile is a StructureDefinition that tightens a resource for one use: in this context, Patient must have an identifier of this type, Observation.code must be a LOINC code from this list, this element must be supported, that one may not appear. An extension adds an element the base resource lacks, identified by a URL and defined by its own StructureDefinition. Implementation guides (US Core, the IPS, national guides) are collections of profiles, extensions, value sets and examples. A resource says which profiles it claims to follow in meta.profile, and a validator checks it.

What a profile can change

A FHIR profile can change a resource only by narrowing it: tightening cardinality, marking elements as must-support, fixing values or patterns, binding elements to value sets with a strength, slicing lists into named parts, restricting choice types, adding FHIRPath invariants and limiting reference targets. A profile cannot add elements, rename anything or loosen the base specification.

Constraint What it does Example
Cardinality Make optional elements required, or forbid them Patient.identifier 1..*; Patient.photo 0..0
Must support Receivers must be able to store and display the element if sent US Core marks birthDate as must-support
Fixed value or pattern Lock an element to one value Observation.category fixed to vital-signs
Binding Point an element at a value set with a strength Observation.code bound to the vital signs list, required
Slicing Split a list into named parts with their own rules Blood pressure: component sliced into systolic and diastolic
Type restriction Limit a choice value[x] restricted to valueQuantity
Invariant A FHIRPath rule that must hold "effective[x] must be present" or "value or dataAbsentReason"
Reference target Limit what a reference may point to subject only Patient, and only patients conforming to this profile

A profile can only narrow. It cannot add elements (that is what extensions are for), rename anything or loosen the base.

Binding strength

FHIR defines four binding strengths. required: the code must come from the value set. extensible: use the value set if a concept fits; otherwise another code is allowed. preferred: recommended, not enforced. example: illustrative only, which is what most base resources have. Misreading extensible as required is a common source of false validation errors.

A readable profile excerpt

A FHIR profile is a StructureDefinition whose differential lists only the constraints that differ from the base resource, while its snapshot lists every element. The readable excerpt below constrains Observation to a home blood pressure: the code is fixed to LOINC 85354-9 and component is sliced into exactly one systolic and one diastolic part.

A profile's differential lists only what changed from the base; the snapshot lists everything. This differential says that a blood pressure Observation must carry LOINC 85354-9 and exactly two components:

{
  "resourceType": "StructureDefinition",
  "url": "https://example.org/fhir/StructureDefinition/bp-home",
  "name": "HomeBloodPressure",
  "status": "active",
  "kind": "resource",
  "abstract": false,
  "type": "Observation",
  "baseDefinition": "http://hl7.org/fhir/StructureDefinition/Observation",
  "derivation": "constraint",
  "differential": {"element": [
    {"id": "Observation.code", "path": "Observation.code",
     "patternCodeableConcept": {"coding": [{"system": "http://loinc.org", "code": "85354-9"}]}},
    {"id": "Observation.component", "path": "Observation.component", "min": 2, "max": "2",
     "slicing": {"discriminator": [{"type": "pattern", "path": "code"}], "rules": "closed"}},
    {"id": "Observation.component:systolic", "path": "Observation.component", "sliceName": "systolic", "min": 1, "max": "1"},
    {"id": "Observation.component:systolic.code", "path": "Observation.component.code",
     "patternCodeableConcept": {"coding": [{"system": "http://loinc.org", "code": "8480-6"}]}},
    {"id": "Observation.component:diastolic", "path": "Observation.component", "sliceName": "diastolic", "min": 1, "max": "1"},
    {"id": "Observation.component:diastolic.code", "path": "Observation.component.code",
     "patternCodeableConcept": {"coding": [{"system": "http://loinc.org", "code": "8462-4"}]}}
  ]}
}

Profiles are rarely written by hand; authors use FHIR Shorthand (FSH) with SUSHI, or tools such as Forge and Simplifier, and publish with the HL7 IG Publisher. Guides are distributed as packages (hl7.fhir.us.core#6.1.0, hl7.fhir.uv.ips#1.1.0) that validators and servers load.

Extensions

An extension is a key-value element placed in extension (or modifierExtension when it changes the meaning of the resource and must not be ignored). Its url is the canonical URL of its StructureDefinition; its value is one typed value[x], or nested extensions. Birth place is an HL7-defined extension on Patient:

{
  "resourceType": "Patient",
  "id": "example",
  "extension": [{
    "url": "http://hl7.org/fhir/StructureDefinition/patient-birthPlace",
    "valueAddress": {"city": "Lyon", "country": "FR"}
  }],
  "name": [{"family": "Doe", "given": ["Jane"]}]
}

Rules of good practice: look for an existing extension (HL7's registry and the national guides) before defining one; give it a URL under a domain you control; define it in a StructureDefinition so others can validate it; never use an extension for something a base element already covers.

meta.profile and validation

meta.profile is the list of canonical URLs a FHIR resource claims to conform to, and claiming is not proving. A validator checks the resource against the base specification and against each claimed profile, or against a profile you name. The HL7 reference validator runs locally with packages, and FHIR servers expose a $validate operation that accepts a profile parameter.

meta.profile lists the canonical URLs a resource claims to conform to. Claiming is not proving: a validator checks the resource against the base specification and against every profile claimed (or against a profile you ask it to use). The HL7 reference validator (validator_cli.jar) runs locally and loads packages; servers offer POST /Observation/$validate?profile=…; the IG Publisher validates all examples in a guide. A resource may conform to several profiles at once (a national Patient profile and the IPS Patient) as long as they do not contradict.

Two practical rules: a server that declares a profile in its CapabilityStatement should reject resources that fail it; a client that receives resources should not reject unknown extensions or extra elements that a profile did not forbid, because the base specification allows them.

In Anpheros

Anpheros Platform is a FHIR R4 server that uses LOINC for observations, ATC for medications and SNOMED CT where applicable, and offers a free validator that checks a resource's structure against FHIR R4. When a clinic sends resources with meta.profile set to a national or IPS profile, the claim is preserved so a downstream system can validate against it.

The free validator is on the developer site. For the guides themselves, see FHIR implementation guides explained.

Sources

Frequently asked questions

Can a profile add a new element to a resource?

No. Profiles only constrain. New data goes in an extension, which the profile can then require or forbid like any other element.

What does must-support actually require?

The implementation guide defines it; typically that a sender populates the element when it has the data and a receiver stores and can display it. It does not make the element mandatory.

If a resource has no meta.profile, is it invalid?

No. meta.profile is a claim, not a requirement. A server or guide may require it; the base specification does not. Validators can be asked to check against a profile the resource does not declare.

How do I know which profile to use in my country?

Each national FHIR community publishes a core guide (US Core, UK Core, nl-core, the German Basisprofile, and so on); the implementation guides page explains how to find them. Cross-border summaries use the IPS.

Anpheros Platform

Try it free in the sandbox

Your first FHIR call in 5 minutes. An HL7 FHIR R4 API with the patient's consent built in: try it in the sandbox, then connect your own app or clinic system.

Free · 30 synthetic patients · no card

This guide is for information and does not replace medical advice. For decisions about your health, talk to your doctor. In an emergency, call your local emergency number (112 in Europe).
Written by
The Anpheros team

Anpheros builds a medical record that the patient controls and can share with any clinic, on an HL7 FHIR R4 platform, based in the EU. These guides help you understand and organise your health; they do not replace your doctor.

About Anpheros →
Anpheros

The more you log, the clearer your record

Your health history in one place, under your control.

Symptom diaryPatterns show over time
Emergency cardQR in your phone's Wallet
All your resultsLabs and reports together
You decideWho sees what, and for how long
Create your free account

Free · Works in your browser · No card