Overview
The bulkhead pattern isolates resources so a failure or overload in one part of a system cannot consume everything and take down the rest. The name comes from ships, whose hulls are divided into watertight compartments: a breach floods one compartment, not the whole ship.
In software, bulkheads are separate thread pools, connection pools, concurrency limits, queues, or even separate deployments per dependency, feature, or customer tier. If the recommendations service hangs, only the resources dedicated to it are exhausted, and checkout keeps working.
If the hull is breached, water fills only one compartment and the ship stays afloat. Without compartments, one hole sinks everything.
When to use it
- Services calling several dependencies of different criticality.
- Multi-tenant systems where one tenant must not starve others.
- Separating critical from non-critical workloads.
- Protecting shared infrastructure (databases, thread pools).
Where it shows up in interviews
Recognize it when: a slow non-critical dependency exhausts threads.
- Design a resilient product page
- Design an API gateway
Recognize it when: one big customer's load hurts others.
- Design a multi-tenant SaaS
- Design a public API platform
Where it is used in real software
Netflix gave each dependency its own thread pool so one failing service could not starve others.
Customers are split across independent cells, a large-scale bulkhead limiting blast radius.
Job systems use separate queues and workers for critical (payments) vs bulk (reports) work.
Key terms
- Resource isolation
- Dedicated pools or limits per consumer or dependency.
- Semaphore bulkhead
- Limit concurrent calls with a counter.
- Thread-pool bulkhead
- Separate thread pool per dependency.
- Cell
- Independent full stack serving a subset of users.
- Noisy neighbor
- A workload consuming shared resources unfairly.
How it works, step by step
- 1Identify shared resources
Threads, connections, CPU, queues, databases.
- 2Classify by criticality
Checkout vs recommendations; paying vs free tier.
- 3Allocate separate limits
Pools or semaphores sized per dependency.
- 4Reject when full
Fail fast with fallback instead of queuing forever.
- 5Monitor saturation
Alert when a bulkhead is frequently full.
Shared vs bulkheaded thread pool
200 request threads; recommendations service hangs
| Setup | Threads stuck on recommendations | Checkout requests | Result |
|---|---|---|---|
| Shared pool | All 200 over time | No threads left | Entire service down |
| Bulkhead: max 20 concurrent recommendation calls | 20 | 180 threads available | Checkout unaffected; recs fall back |
NOWSetup: Shared pool | Threads stuck on recommendations: All 200 over time | Checkout requests: No threads left | Result: Entire service down
The bulkhead converts a total outage into a degraded feature.
Implementation
// Semaphore bulkhead: limit concurrent calls per dependency and reject when fullexport class Bulkhead { private active = 0; constructor(private readonly maxConcurrent: number, private readonly name: string) {} async run<T>(fn: () => Promise<T>, fallback: () => T): Promise<T> { if (this.active >= this.maxConcurrent) { metrics.increment("bulkhead.rejected", { name: this.name }); return fallback(); } this.active++; try { return await fn(); } finally { this.active--; } }} const recommendationsBulkhead = new Bulkhead(20, "recommendations");const inventoryBulkhead = new Bulkhead(100, "inventory"); const recs = await recommendationsBulkhead.run(() => withTimeout(recsClient.similar(id), 200), () => []);Complexity and performance
Counter or pool.
Plus headroom.
Trade-offs
Dedicated pools can sit idle while another pool is saturated; shared pools are more efficient but less safe.
More bulkheads isolate better but require more tuning.
Variants and related techniques
Run critical and non-critical endpoints on different instances.
Bulkheads at the tenant level.
Common mistakes
- Sizing bulkheads by guesswork.
Fix: Use Little's Law with measured rates and latencies.
- Unbounded queues in front of bulkheads.
Fix: Queues hide saturation and add latency; bound them.
Interview questions
What is the bulkhead pattern?
Isolating resources, such as thread pools, connection pools, or concurrency limits, per dependency, feature, or tenant so that exhaustion in one area cannot take down the whole service.
How do you prevent one tenant from affecting others in a SaaS?
Per-tenant rate limits and quotas, separate queues or worker pools for large tenants, sharding or cells to place tenants in isolated infrastructure, and monitoring per tenant.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| Implement a semaphore bulkhead | Easy | Concurrency limits. |
| Design tenant isolation for a multi-tenant API | Hard | Cells and quotas. |