← Core Resources
Track 1 — FHIR Fundamentals

Bundle

A Bundle is a container for multiple FHIR resources. It groups resources into a single HTTP request or response. The Bundle type determines what the server does with it — and what it means.

Bundle types

The type field is the most important field in a Bundle. It dictates the processing semantics. Two Bundles with identical content but different types are processed completely differently.

TypeDirectionSemantics
transactionRequestAtomic — all entries succeed or all fail together
batchRequestEach entry processed independently, partial success allowed
searchsetResponseSearch results — returned by GET /Patient?name=...
historyResponseVersion history — returned by GET /Patient/1/_history
documentBothClinical document — first entry must be Composition
collectionBothGrouping resources — no processing semantics

Transaction Bundle: creating multiple resources atomically

A transaction Bundle is sent to the base URL (POST /fhir/). The server processes all entries as a single atomic operation. If any entry fails validation or conflicts, the entire transaction rolls back — no partial saves.

The key challenge in transactions: resources often reference each other. A Condition references a Patient. If both are created in the same transaction, the Patient doesn't have a server-assigned ID yet. The solution is urn:uuid references.

POST http://localhost:8080/fhir/

{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry": [
    {
      "fullUrl": "urn:uuid:a1b2c3d4-0001-0000-0000-000000000001",
      "resource": {
        "resourceType": "Patient",
        "name": [{ "family": "Horváth", "given": ["Jana"] }],
        "gender": "female",
        "birthDate": "1979-03-12"
      },
      "request": { "method": "POST", "url": "Patient" }
    },
    {
      "fullUrl": "urn:uuid:a1b2c3d4-0002-0000-0000-000000000002",
      "resource": {
        "resourceType": "Condition",
        "clinicalStatus": {
          "coding": [{ "code": "active" }]
        },
        "code": {
          "coding": [{ "system": "http://snomed.info/sct", "code": "44054006" }]
        },
        "subject": {
          "reference": "urn:uuid:a1b2c3d4-0001-0000-0000-000000000001"
        }
      },
      "request": { "method": "POST", "url": "Condition" }
    }
  ]
}
The Condition references the Patient using its urn:uuid:... fullUrl. The server resolves all internal references after assigning real IDs, then writes everything in a single database transaction.

Transaction entry structure

fullUrlTemporary identifier for this entry within the Bundle. For new resources: urn:uuid:... For updates: the existing resource URL. Used to build internal cross-references.
resourceThe FHIR resource to create, update, or delete. Must be a complete, valid resource.
request.methodHTTP method: POST (create), PUT (update or create with known ID), DELETE (delete), GET (read — valid only in batch, not transaction).
request.urlThe relative URL for the operation. For POST: resource type (Patient). For PUT: resource type + ID (Patient/123). For conditional create: Patient?identifier=system|value.
request.ifNoneExistConditional create. If a resource matching this search string already exists, skip this entry instead of creating a duplicate. e.g. identifier=http://example.sk/pid|7903121234

transaction vs batch — when to use which

transaction
  • Creating linked resources together
  • Data must be consistent as a set
  • Partial failure is not acceptable
  • Example: Patient + Condition + MedicationRequest for the same patient — if the Patient fails, the rest should not be saved.
batch
  • Independent operations in one round-trip
  • Some may succeed even if others fail
  • Loading historical data from a CSV
  • Example: importing 100 Patient records — a validation error on record 47 should not block the other 99.

See also