Chapter 9: Multi-Warehouse Architecture
Why This Exists
If you only have one warehouse in New York, and a customer in Los Angeles orders a product, shipping it across the country will take five days and cost $15. If your competitor has a warehouse in California, they can deliver it tomorrow for $5. Multi-warehouse architecture exists to solve the physics of logistics—placing inventory closer to the buyer to decrease shipping times, lower fulfillment costs, and build a resilient supply chain that survives regional disasters.
Real World Problem
A merchant upgrades to a second warehouse. A customer orders a Shirt (which is in Warehouse A) and a Hat (which is in Warehouse B). The legacy software assumes one order equals one shipment. It sends the entire order to Warehouse A. Warehouse A ships the shirt, but they don't have the Hat, so the order stays "Pending" forever. The customer never gets their Hat. The real-world problem is that expanding to multiple locations breaks the fundamental assumption that an order is a single, unified entity.
Everyday Analogy
Think of ordering a pizza from a large chain like Domino's. You open the app and place an order. The app doesn't send your order to the corporate headquarters in Michigan to be baked and mailed to you. The central system looks at your GPS coordinates, finds the specific franchise location 2 miles from your house, and routes the order directly to their kitchen.
Beginner Explanation
When you have multiple buildings full of stuff, the computer has to make a choice every time an order is placed. Instead of just saying, "Ship it," the computer asks:
- Where does the customer live?
- Which buildings have the item in stock?
- Which of those buildings is closest to the customer? It then tells the closest building to put the item in a box and mail it.
Intermediate Explanation
Moving to multiple warehouses introduces the concept of Order Routing (or Distributed Order Management - DOM).
When an order is created, it must be split into Fulfillments. If a customer orders Item X and Item Y:
- The system checks inventory at Location 1 and Location 2.
- If Location 1 has both, the system creates one fulfillment assigned to Location 1.
- If Location 1 only has X, and Location 2 only has Y, the system creates two fulfillments. The customer will receive two separate boxes, with two separate tracking numbers, arriving on different days. The UI and database must be designed to handle this "Split Shipment" reality.
Advanced Explanation
At enterprise scale, proximity isn't the only factor. Order Routing becomes a complex algorithmic optimization problem calculating the "Cost to Serve."
The system evaluates rules dynamically:
- Distance: Ship from the closest node.
- Stock Buffers: If Warehouse A only has 1 left, and Warehouse B has 500, ship from B to prevent stockouts in A.
- Labor Costs: If Warehouse A is paying weekend overtime rates, route the order to Warehouse B.
- Box Consolidation: Is it cheaper to pay $20 to ship one big box from across the country, or $10 each to ship two small boxes from local warehouses?
This requires a dedicated Rules Engine that evaluates every order in milliseconds before committing the ledger transaction.
Real World Example
Amazon's Predictive Logistics: Amazon doesn't just route orders after you buy them; they route inventory before you buy it. Using AI and historical data, if they predict that 10,000 people in Chicago will buy a specific snow shovel next week, they will move those shovels from a central hub into local Chicago distribution centers today. When you click "Buy," the item is already 5 miles from your house, enabling Same-Day Delivery.
Architecture Design
Here is how a Distributed Order Management (DOM) system handles routing:
graph TD
Order[New Order Received] --> DOM[Order Routing Engine]
DOM -->|Check Stock| Inv_DB[(Global Inventory DB)]
DOM -->|Check Distance| Geo[Geo-Routing Service]
DOM -->|Evaluate Cost| Rules[Business Rules Engine]
Rules -- Optimal Route Chosen --> Split{Split Order?}
Split -- No (Single Box) --> W1[Warehouse A API]
Split -- Yes (Two Boxes) --> W1
Split -- Yes (Two Boxes) --> W2[Warehouse B API]
Database Design
To support multi-warehouse routing, the database schema must decouple Orders from Fulfillments.
1. Inventory Levels (Location-Aware):
CREATE TABLE inventory_levels (
sku VARCHAR(100),
location_id INT,
available_quantity INT,
PRIMARY KEY (sku, location_id)
);
2. Order Fulfillments:
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT,
total DECIMAL(10,2)
);
CREATE TABLE fulfillments (
id INT PRIMARY KEY,
order_id INT,
location_id INT, -- Which warehouse is packing this?
status VARCHAR(50), -- 'PENDING', 'SHIPPED'
tracking_number VARCHAR(100)
);
CREATE TABLE fulfillment_lines (
fulfillment_id INT,
sku VARCHAR(100),
quantity INT
);
Note: One Order can have multiple Fulfillments.
API Design
Order Routing (Internal API):
POST /api/internal/orders/route
Payload: { "order_id": 1234, "shipping_address": {...} }
Response:
{
"fulfillments": [
{ "location_id": 1, "items": [{"sku": "SHIRT", "qty": 1}] },
{ "location_id": 2, "items": [{"sku": "HAT", "qty": 1}] }
]
}
Production Considerations
- Eventual Consistency in Routing: If an order is routed to Warehouse A, but Warehouse A physically lost the item 5 minutes ago, Warehouse A must "reject" the fulfillment. The DOM system must listen for this rejection event and re-route the fulfillment to Warehouse B.
- API Rate Limiting: 3PLs (Third-Party Logistics providers like ShipBob) have strict API rate limits. If you have a flash sale and send 10,000 fulfillment requests to their API at once, they will ban your IP. Fulfillments must be queued and processed at a controlled rate.
Security Considerations
- Webhook Validation: Warehouses communicate back to the e-commerce system via Webhooks (e.g., "Order Shipped!"). These endpoints must cryptographically verify the payload signature to ensure malicious actors aren't spoofing shipping confirmations to trigger fraudulent refunds.
Common Mistakes
- Hardcoding the Location: Writing frontend or backend code that assumes
inventory = product.stock. It must always beinventory = sum(product.locations.stock). - Ignoring the UI Impact: Designing an "Order Status" page that only has one tracking number field. If the order is split into three boxes, the UI must display three distinct progress bars and tracking links.
Tradeoffs and Alternatives
- Store Fulfillment vs. Dedicated Warehouses: Many retailers use their physical retail stores as mini-warehouses (Ship-from-Store). This saves money on warehouse leases but introduces chaos, as store inventory is highly inaccurate due to shoplifting and customers carrying items around the store during the sync period.
Interview Questions
- A customer orders two items. One is in NY, one is in LA. How do you design the database schema to handle shipping these separately?
- What is an Order Routing Engine, and what variables should it consider besides geographic distance?
- What happens if an order is routed to a warehouse, but the warehouse staff cannot find the item on the shelf? Explain the system flow to recover from this.
Hands-On Exercise
- You have 3 warehouses: East, Central, West.
- A customer in California (West) orders: Laptop, Mouse, Keyboard.
- Inventory:
- East: [Laptop, Mouse, Keyboard]
- Central: [Laptop, Mouse]
- West: [Keyboard]
- Using a whiteboard, trace two different routing logic paths:
- Path A: Optimize for fewest boxes (Cheapest shipping).
- Path B: Optimize for fastest delivery to the customer.
Key Takeaways
- Multi-warehouse architectures break the assumption that an Order is a single physical shipment.
- Orders must be split into Fulfillments assigned to specific locations.
- Distributed Order Management (DOM) systems use algorithmic rules to balance shipping speed against shipping costs.
- The UI and Database must be explicitly designed to handle split shipments and multiple tracking numbers per order.
Further Reading
- "The Supply Chain Revolution" by Suman Sarkar
- AWS Architecture Blog: Distributed Order Management Systems