
FHIR gives two ways to point one resource at another: contain it inside the parent, or reference it externally by URL. The two look similar in the payload and behave very differently at resolution time. Contained is cheaper to resolve, harder to reuse, and safer against outages. External is easier to reuse, harder to resolve, and requires the target to be reachable. Picking the wrong one at design time bakes in costs that surface later. The site's Bundle reference walker shows how the resolver treats each shape. For the wider FHIR framing, the Da Vinci ecosystem hub has more.
The Shapes on the Wire
Contained lives inside the parent, keyed by a local id. Reference points at it with a hash prefix:
`` "contained": [{ "resourceType": "Medication", "id": "med1", ... }], "medicationReference": { "reference": "#med1" } ``
External sits in a separate resource, referenced by relative or absolute URL:
`` "medicationReference": { "reference": "Medication/54321" } ``
Same wire shape on medicationReference, radically different resolution mechanics.
Cost At Resolution Time
- Contained — O(1) lookup inside the parent's
contained[]array. No network. No cache. Always available if the parent is. - External relative — one lookup against the local index (if inside a Bundle) or one remote GET (if standalone).
- External absolute — one remote GET, subject to network latency and target-server availability.
For a Bundle full of references that could go either way, contained resolves in microseconds. External resolves in whatever the target server can serve, cached or not.
For the base pattern, resolving FHIR references without a full database walk is the entry.
Safety Under Outages
Contained cannot fail unless the parent is inaccessible. External can fail whenever the target server is unreachable, slow, or returning an error. That difference matters for workloads that need to render or process a resource offline — a MedicationRequest with a contained Medication is self-sufficient; one with an external Medication reference needs the target to be up.
When Contained Wins
- One-off compound or preparation with no catalog entry
- Data that is only meaningful in the context of the parent
- Receivers with no lookup capability against the target resource type
- Situations where the parent has to be self-contained for offline use
Contained is the escape hatch for entities that legitimately live only inside their parent. Using it for entities that have external identity fragments that identity across parents, and that is a data-quality problem waiting to bite.
When External Wins
- Entities with independent identity (Patient, Practitioner, Organization)
- Data that gets referenced from many places
- Receivers with full lookup capability against the target
- Situations where updates to the referenced resource should propagate
External is the default. Contained is the exception. For the distributed-deployment version of this question, reference integrity in a distributed FHIR deployment covers the mechanics.
The Circular Trap
Both shapes can produce circles. A contained resource that references its parent, or two contained resources that reference each other, creates a cycle. External references produce cycles across resource graphs. Either way, the resolver has to detect them or blow the stack. For the pattern, circular references and how to detect them safely is the entry.
What Not to Do
Do not contain a Patient, Practitioner, or Organization inside another resource. Do not use external references for one-off entities that have no independent identity. Do not mix the two for the same conceptual entity across payloads.
The Short Version
Contained is cheap and safe; use it for entities with no external identity. External is default and flexible; use it for anything with independent identity. Both can cycle. The walker shows each shape resolved live against a paste-in Bundle.

Sources
- HL7 canonical section on contained resources - HL7 canonical section on contained resources