Parallelizing a FHIR import is the single biggest lever for cutting duration. Running eight workers instead of one drops the wall clock by a factor of four to seven. But naïve parallelization corrupts references — worker A writes an Observation before worker B writes the Patient it references, and the reference lands dangling. Handling that ordering constraint is the specific discipline of parallel FHIR imports. The site's Bulk import time estimator factors parallelism into its output. For the wider FHIR framing, the FHIR field guide here on the site has more.
The Reference Ordering Problem
- Observation references Patient
- Patient must be written before Observation, or the reference is broken
- If workers write in parallel without coordination, the order is arbitrary
Naïve parallelism produces broken references.
For the base ETA framing, predicting how long a FHIR data import will take is the entry.
Solution One: Type-Ordered Passes
- Pass 1: write all Patients in parallel
- Pass 2: write all Practitioners in parallel
- Pass 3: write all Observations, MedicationRequests, etc. in parallel
Each pass finishes before the next starts. Within a pass, workers are safe because entries reference resources from prior passes.
Simple, correct, slightly slower than fully parallel.
Solution Two: Reference Batches
Group resources by their reference dependencies. All entries in a batch reference only resources from earlier batches or the current batch.
More complex to compute up front, more efficient to run.
For the driver-analysis side, the four dominant drivers of import duration is the entry.
Solution Three: Lax-Integrity Server Plus Verification Pass
If the server tolerates dangling references (many do by default), write everything in parallel and verify integrity after.
Fastest during the write. Adds a verification pass afterward. Right when the verification pass fits in the schedule.
The Batch Size Question
Each worker processes a batch of resources per transaction. Bigger batches = fewer round trips. Smaller batches = smaller retries.
- 100 resources per batch — reasonable default for most servers
- 500 — some servers benefit
- 5000 — usually too large
Tune per server.
The Worker Count
Server sustained throughput divided by per-worker throughput = optimal worker count. Beyond that, adding workers produces contention, not throughput.
For a server that sustains 1000 writes/second and per-worker throughput of 200 writes/second, five workers is optimal. Eight workers produces contention and worse throughput than five.
Measure both. Do not guess.
The urn:uuid: Case
Transaction Bundles use urn:uuid: for cross-entry references. Parallel workers writing Bundles that reference each other's URNs is a mess.
Rule: URNs are Bundle-local. Do not use urn:uuid: for cross-batch references. Use real ids or Reference.identifier.
Failure Isolation
- One worker fails — other workers keep going
- One batch fails — retry the batch on a different worker
- Whole import fails — recover from the failure point
Design for failure per batch, not per import. For the recovery side, recovering from a failed import without starting over is the entry.
Read-After-Write Contention
Some parallel imports read the just-written data during subsequent writes. If the server has read-after-write inconsistency, you get flakes.
- Wait for write confirmation before dependent read
- Use strongly-consistent read APIs
- Retry with backoff on read-not-found
Rate Limiting Coordination
Parallel workers can collectively exceed the server's rate limit even if each worker is under it. Coordinate the fleet's request rate, not just per-worker rate.
Simplest coordination: single token bucket in a small shared cache. Workers acquire tokens before each request.
The Metrics Question
Every worker should emit:
- Requests per second
- Success rate
- Retry rate
- Batch size
Aggregate across workers to get the fleet's actual throughput. For monitoring, monitoring an in-flight import for the numbers that matter is the entry.
The Short Version
Type-order passes, reference batches, or lax + verification. Batch size matters. Worker count matches sustained throughput. Coordinate rate limits across workers. Design for per-batch failure. That is parallel FHIR import that survives.

Sources
- HTML - HTML, HL7 FHIR - References and how they work