FHIR integration guide

FHIR References Explained: Relative, Absolute, Contained and Bundle fullUrl Links

An unresolved FHIR reference means the consumer cannot identify the intended target using the reference form and context it received. Check the literal or logical reference, the containing resource, the Bundle entry's fullUrl, and whether the link is expected to resolve locally or through a server. This guide explains those rules and the failures that occur when otherwise valid resources use inconsistent identities.

By Health Data ToolsPublished 27 July 2026Technically reviewed 27 July 2026Approx. 13-minute read
Use synthetic resources when troubleshooting. FHIR payloads can contain patient data, identifiers, clinical results, access tokens and internal service addresses. Remove or replace those values before sharing a resource, Bundle, log or validation report.

Overview

A reference identifies a target; it does not embed the target resource

FHIR resources use references to connect information that is represented separately. An Observation.subject, for example, can identify the Patient to whom a result belongs. The relationship is expressed from the Observation to the Patient and does not imply that the Patient resource is physically present in the same payload.

{
  "resourceType": "Observation",
  "id": "result-1",
  "status": "final",
  "subject": {
    "reference": "Patient/patient-1"
  }
}

FHIR R4 defines the Reference data type with a literal reference, a logical identifier, an optional target type, and a short display description. At least one of reference, identifier or display must be present unless an extension provides the content.[1]

Unresolved does not always mean invalid. A reference to a remote resource can be meaningful even when an offline viewer cannot retrieve it. The failure is actionable when the target should be present in the same Bundle, a contained-resource fragment has no matching ID, or the destination server cannot resolve a reference required by the transaction.

Reference fields

Literal, logical and display values serve different purposes

FieldPurposeExample
referenceLiteral relative, absolute, internal-fragment or version-specific reference to a resource.Patient/patient-1
identifierLogical reference using a business identifier when a literal resource URL is not known.https://example.test/mrn | MRN-1001
typeStates the expected resource type when resolving the target is slow or unavailable.Patient
displayProvides a short human-readable description of the target.Synthetic patient 1001

If type is supplied, it must agree with the resolved resource type. The display value helps a user understand the link when the target cannot be retrieved, but it is not a substitute for the target resource and should not be used as its identity.

A logical identifier is not a literal resource URL

"subject": {
  "type": "Patient",
  "identifier": {
    "system": "https://example.test/mrn",
    "value": "MRN-1001"
  },
  "display": "Synthetic patient 1001"
}

A system can resolve this only if it understands the identifier system and the business context in which it is used. FHIR does not require a server to turn every Reference.identifier into a literal URL automatically. A receiving server may retain it, resolve it or reject it according to its capabilities and profile rules.[1]

Literal references

Relative, absolute, contained and version-specific links resolve differently

FormExampleResolution context
RelativePatient/patient-1Relative to the FHIR service base, or to the base implied by the containing Bundle entry's RESTful fullUrl.
Absolutehttps://api.example.test/fhir/Patient/patient-1Matches an entry with the same fullUrl or is retrieved from the stated URL when permitted.
Contained#practitioner-1Matches a resource in the current container resource's contained array.
Version-specificObservation/result-1/_history/3Targets a particular resource version rather than the current version.
Transaction UUIDurn:uuid:11111111-1111-4111-8111-111111111111Matches the temporary identity in another transaction entry's fullUrl.

Literal reference URLs are case-sensitive. Patient/patient-1 and Patient/Patient-1 therefore identify different URLs even when a local database treats identifiers as case-insensitive.[1]

Canonical references are a separate data type

Elements of type canonical identify conformance, terminology or knowledge artifacts through their canonical url, optionally followed by a business version using the |version syntax. That version is not the same as Resource.meta.versionId. Do not apply ordinary Reference or REST history rules to a canonical value without checking the element's declared data type.

Bundle identity

Bundle.entry.fullUrl identifies the resource carried by that entry

Except for the transaction and batch exceptions defined by FHIR R4, each Bundle entry must have a fullUrl that gives the identity of its resource. A persistent absolute URL can be used when one exists. When the resource has no suitable persistent identity, the specification recommends a urn:uuid: value.[2]

{
  "fullUrl": "https://api.example.test/fhir/Patient/patient-1",
  "resource": {
    "resourceType": "Patient",
    "id": "patient-1"
  }
}

The fullUrl is not the Bundle's ID, the entry's array position or a display label. It is also not version-specific: FHIR R4 prohibits /_history/ in Bundle.entry.fullUrl. Version-specific references are matched to the unversioned fullUrl and then to Resource.meta.versionId.[2]

How a relative reference is resolved inside a Bundle

For a relative type/id reference, the processor first considers the fullUrl of the entry containing the source resource. If that fullUrl is RESTful, its service root is combined with the relative reference and the resulting absolute URL is matched against Bundle entry identities. For an absolute reference, the processor looks directly for a matching fullUrl before attempting external retrieval.[2]

Source entry fullUrl:
https://api.example.test/fhir/Observation/result-1

Reference in that Observation:
Patient/patient-1

Resolved candidate:
https://api.example.test/fhir/Patient/patient-1

This is why comparing only entry.resource.id is insufficient. Bundle resolution depends on the reference form, source-entry identity, target fullUrl and, for version-specific links, meta.versionId.

Transaction example

Use matching urn:uuid values for resources created together

A transaction can create several resources whose server-assigned IDs are not yet known. Give each new entry a distinct UUID fullUrl and use that exact URI wherever another entry references it. When the server assigns the permanent IDs, it must update matching references within the transaction as part of processing.[3]

{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry": [
    {
      "fullUrl": "urn:uuid:11111111-1111-4111-8111-111111111111",
      "resource": {
        "resourceType": "Patient",
        "name": [{ "family": "SAMPLE", "given": ["Alex"] }]
      },
      "request": { "method": "POST", "url": "Patient" }
    },
    {
      "fullUrl": "urn:uuid:22222222-2222-4222-8222-222222222222",
      "resource": {
        "resourceType": "Observation",
        "status": "final",
        "code": {
          "text": "Synthetic test result"
        },
        "subject": {
          "reference": "urn:uuid:11111111-1111-4111-8111-111111111111"
        }
      },
      "request": { "method": "POST", "url": "Observation" }
    }
  ]
}

The Observation does not reference Patient/11111111-.... It references the complete temporary URI used by the Patient entry. Changing one side to a relative Patient/id form without a resolvable RESTful identity creates a different reference and can leave the transaction link unresolved.

Batch and transaction are not interchangeable here. FHIR R4 treats a transaction as atomic and allows references between resources being created together. A batch processes entries independently; references to another resource being created within the same batch are non-conformant.[3]

Advertisement

Contained resources

A #fragment reference stays inside its container resource

A contained resource is used when the target does not have an independent identity outside its containing resource. The contained resource has a local id, and the reference uses that ID with a leading #.[1]

{
  "resourceType": "Condition",
  "id": "condition-1",
  "contained": [
    {
      "resourceType": "Practitioner",
      "id": "practitioner-1",
      "name": [{ "family": "SAMPLE", "given": ["Pat"] }]
    }
  ],
  "asserter": {
    "reference": "#practitioner-1"
  }
}

The processor resolves #practitioner-1 only within this Condition. It must not search another Bundle entry or remote server for that fragment. FHIR R4 also prohibits nested contained resources and requires a contained resource to be referenced from within its container relationship.

Containment should not be used merely to avoid assigning a proper resource identity. Once a target can be independently identified and reused, a normal literal reference is usually the clearer representation.

Failure patterns

Common reasons a FHIR reference does not resolve

SymptomLikely causeWhat to compare
Bundle viewer reports a missing PatientThe relative Patient/id does not produce a URL matching any entry fullUrl.Source entry fullUrl, target fullUrl, resource type and ID.
Transaction server rejects an inter-entry referenceThe reference does not exactly match the target entry's temporary UUID URI.Complete urn:uuid: strings on both entries, including spelling and case.
Contained reference has no targetThe fragment ID is absent, duplicated or placed in a different resource.#id value and the current container's contained[].id values.
Reference resolves to the wrong typeReference.type, path expectations or target content disagree.Declared target types, resolved resourceType and applicable profile.
Only version-specific lookup failsThe logical resource exists but the requested meta.versionId does not.Unversioned identity, history support and exact version ID.
Logical identifier cannot be resolvedThe receiver does not recognise the identifier system or has multiple matches.identifier.system, identifier.value, target type and server policy.
Reference works on one server onlyA relative URL was interpreted against a different service base or Bundle context.Base URL, source-entry fullUrl, proxy paths and server CapabilityStatement.
Canonical URL was rewritten like a transaction referenceThe implementation treated a canonical element as an ordinary Reference.Element data type, canonical URL and optional |version.

Troubleshooting

A repeatable FHIR reference investigation

  1. Capture the exact resource or Bundle. Work from the transmitted JSON before logs, formatters or mapping layers change it.
  2. Locate the failing element. Record its FHIR path, declared data type, reference, identifier, type and display.
  3. Classify the reference form. Decide whether it is relative, absolute, contained, version-specific, logical, canonical or a transaction UUID.
  4. Identify the expected resolution scope. Determine whether the target should be contained, present in the Bundle, available from the same FHIR service or resolved through business identifiers.
  5. Inspect the source entry. For a Bundle, record the fullUrl of the entry containing the reference.
  6. Build the candidate target identity. Apply the Bundle and relative-URL rules rather than matching only resource.id.
  7. Check for zero or multiple matches. Both conditions require attention; silently choosing the first matching entry can hide an ambiguous Bundle.
  8. Check version and type separately. Confirm meta.versionId for version-specific links and resourceType against the allowed target types.
  9. For transactions, compare every temporary identity. Ensure each inter-entry reference exactly matches one fullUrl and that the Bundle type is transaction, not batch.
  10. Apply the destination's profile and capabilities. Core FHIR rules do not replace implementation-guide constraints or the server's supported reference policies.

The FHIR JSON Formatter & Resource Viewer lists reference paths, indexes Bundle fullUrl values and resource IDs, and separates unresolved internal links from references that may require an external server. Use it to understand the payload before moving to profile validation.

Checklist

What to define in a FHIR integration

  • The FHIR version and implementation guide used by both sender and receiver.
  • Which reference forms are accepted for each profile and target element.
  • The service base used to resolve relative references outside a Bundle.
  • How Bundle fullUrl values are generated, normalised and checked for duplicates.
  • Whether transaction creates use stable UUID URIs for inter-entry links.
  • How logical identifiers are mapped to resource identities and how multiple matches are handled.
  • Whether version-specific references are supported and how unavailable history is reported.
  • Whether external URLs may be retrieved, and which authentication and network controls apply.
  • How contained-resource fragment IDs are validated within each container.
  • How canonical elements are kept separate from ordinary Reference processing.
  • What diagnostic output can be retained without logging patient data or access credentials.

FAQ

Frequently asked FHIR reference questions

Does every reference need to resolve inside the same Bundle?

No. A Bundle can contain references to resources that are retrieved externally or resolved through other supported mechanisms. A link is a Bundle error when its context requires an included target and the defined Bundle resolution process cannot identify one.

Is Bundle.entry.fullUrl the same as resource.id?

No. resource.id is the logical ID within a resource identity. entry.fullUrl supplies the entry's complete identity in the Bundle, such as an absolute REST URL or urn:uuid: URI. They must be interpreted together when the fullUrl is RESTful.

Can a transaction use Patient/patient-1 to reference a new Patient?

It can only work when that identity is meaningful and resolvable in the transaction context. When the server will assign the Patient's ID, use a UUID fullUrl and reference that exact UUID URI from the other entries.

Can a contained resource be referenced from another Bundle entry?

No. A #fragment reference is resolved within its container resource and does not cross the Bundle.entry.resource boundary.

Is an unresolved logical identifier automatically invalid?

No. A logical reference may be retained when no literal resource URL is known. Whether the receiver must resolve it depends on the profile, workflow and server policy. The receiver needs to understand the identifier system and business context before it can identify a target resource.

Advertisement

Primary references

FHIR R4 reference and Bundle rules

  1. HL7 FHIR R4: Resource References — Reference fields, literal and logical references, canonical URLs, version-specific references and contained resources.
  2. HL7 FHIR R4: BundlefullUrl, entry identity, uniqueness constraints and reference resolution within Bundles.
  3. HL7 FHIR R4: Batch and Transaction Processing — atomic transaction behaviour, inter-entry references, ID assignment and reference replacement.

This guide uses FHIR R4 because the site's viewer summaries and examples currently focus on common R4-style fields. Later FHIR releases and jurisdiction-specific implementation guides may define additional constraints or clarify behaviour.