The Storage Menu
edge platforms expose a small set of purpose-built primitives:
┌────────────────┬───────────────┬──────────────────────────┐
│ PRIMITIVE │ CONSISTENCY │ SHAPE │
├────────────────┼───────────────┼──────────────────────────┤
│ Edge KV │ eventual │ key→value, replicated │
│ │ (reads local) │ globally, ms reads │
├────────────────┼───────────────┼──────────────────────────┤
│ Durable Object │ strong │ stateful actor + its │
│ storage │ (per object) │ embedded storage │
├────────────────┼───────────────┼──────────────────────────┤
│ Blob/R2-class │ strong │ objects/files, S3 API, │
│ object store │ (per write) │ no egress fees │
├────────────────┼───────────────┼──────────────────────────┤
│ Regional SQL │ ACID │ classic database; │
│ (via pooler) │ │ edges are remote clients │
└────────────────┴───────────────┴──────────────────────────┘
Edge KV: Reads Fast, Writes Traveled
mechanics:
write → primary region → async replication to all POPs
read → served from POP-local replica (~1ms)
implications by workload:
✓ config/flags: written rarely, read constantly — perfect
✓ sessions metadata: read-heavy per request lifetime
⚠ counters: last-write-wins on concurrent writes —
increments LOST. use DOs for counting.
✗ anything transactional across keys
Durable Object Storage: Transactional Islands
each actor gets embedded, transactional storage:
class Cart extends DurableObject {
async addItem(item) {
const cart = await this.ctx.storage.get("cart") || [];
cart.push(item);
await this.ctx.storage.put("cart", cart); // atomic w/ state
}
}
properties: strongly consistent with the object's execution;
durable (survives restarts);
single-point serialization = correctness, and also
throughput ceiling PER OBJECT (fine: many objects).
Object Storage at the Edge
R2-class stores change the economics AND the topology:
- zero egress fees → serving user content doesn't bleed money
- S3-compatible API → existing tooling works
- edge workers read/write directly (no origin hop for assets)
patterns:
uploads: presigned URLs or worker-streamed directly to store
delivery: cache in front of store (store = origin)
staging: transcode outputs land here before CDN promotion
When Regional Databases Still Answer
some workloads must not leave classic databases:
- cross-entity transactions (money movement!)
- complex ad-hoc queries/analytics
- strict compliance data residency
edge access pattern then: HTTP-based or pooled connections,
connection-per-request discipline (no long-lived pools at
300 POPs against one primary — you'll exhaust it),
plus aggressive edge caching of READ models in front.
Choosing Per Data Class
| Data | Primitive | Why |
|---|---|---|
| Feature flags | Edge KV | Read-hot, staleness-tolerant |
| Live carts | DO storage | Transactional per-entity |
| User uploads | Object store + CDN | Big blobs, egress economics |
| Orders/payments | Regional SQL | Transactions, truth |
| Rate limits | DO per key | Atomic increments |
Interview Framing
Storage questions test primitive-matching. Scored shape: enumerate the four classes, assign YOUR design’s data classes to them explicitly (flags→KV, carts→DOs, media→R2+CDN, orders→SQL), justify one non-obvious pick (counters→DO because KV loses increments). That table-in-prose form is exactly what senior edge designs look like.
Premium Content
Unlock Edge Storage and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans