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.
| Type | Direction | Semantics |
|---|---|---|
| transaction | Request | Atomic — all entries succeed or all fail together |
| batch | Request | Each entry processed independently, partial success allowed |
| searchset | Response | Search results — returned by GET /Patient?name=... |
| history | Response | Version history — returned by GET /Patient/1/_history |
| document | Both | Clinical document — first entry must be Composition |
| collection | Both | Grouping 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" }
}
]
}urn:uuid:... fullUrl. The server resolves all internal references after assigning real IDs, then writes everything in a single database transaction.Transaction entry structure
transaction vs batch — when to use which
- 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.
- 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.