Skip to main content

Workers KV

Learning Focus

By the end of this lesson you will understand how Workers KV stores and reads data globally, its consistency model, and when to use it vs other storage options.

What Is Workers KV?

Workers KV is a global, low-latency, key-value data store. It's designed for read-heavy workloads where data is written infrequently but read millions of times across 330+ edge locations.

flowchart LR
WORKER["Worker\n(Any PoP)"] -->|Read| KV["KV Store\n(Global Edge Cache)"]
WORKER -->|Write| KV
KV -->|"Propagates in\n~60 seconds"| GLOBAL["All 330+\nEdge Locations"]

style KV fill:#16a34a,color:#fff,stroke:#15803d
style WORKER fill:#f6821f,color:#fff,stroke:#e5711e

Key Characteristics

FeatureDetails
Read latency<10ms (reading from nearest edge)
Write propagationEventually consistent (~60 seconds globally)
Max key size512 bytes
Max value size25 MB
ConsistencyEventually consistent (not strongly consistent)
Best forConfiguration, feature flags, cached API responses, user sessions

Free Tier

ResourceFree Plan
Reads100,000 per day
Writes1,000 per day
Deletes1,000 per day
Lists1,000 per day
Storage1 GB
Namespaces100

Using KV in a Worker

Setup

Create a KV namespace
wrangler kv namespace create MY_KV

# Output:
# Add the following to your wrangler.toml:
# [[kv_namespaces]]
# binding = "MY_KV"
# id = "<namespace-id>"
wrangler.toml
name = "my-worker"
main = "src/index.ts"

[[kv_namespaces]]
binding = "MY_KV"
id = "<namespace-id>"

Basic Operations

src/index.ts
export interface Env {
MY_KV: KVNamespace;
}

export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);

// Write a value
if (url.pathname === "/set") {
await env.MY_KV.put("greeting", "Hello from KV!");
return new Response("Value saved");
}

// Read a value
if (url.pathname === "/get") {
const value = await env.MY_KV.get("greeting");
return new Response(value || "No value found");
}

// Store JSON
if (url.pathname === "/set-json") {
await env.MY_KV.put("user:123", JSON.stringify({
name: "Alice",
role: "admin",
}));
return new Response("JSON saved");
}

// Read JSON
if (url.pathname === "/get-json") {
const user = await env.MY_KV.get("user:123", "json");
return Response.json(user);
}

// Delete a value
if (url.pathname === "/delete") {
await env.MY_KV.delete("greeting");
return new Response("Value deleted");
}

// List keys
if (url.pathname === "/list") {
const keys = await env.MY_KV.list();
return Response.json(keys);
}

return new Response("Not Found", { status: 404 });
},
};

TTL (Expiration)

// Set a value that expires in 1 hour
await env.MY_KV.put("session:abc", "user-data", {
expirationTtl: 3600, // seconds
});

// Set a value that expires at a specific time
await env.MY_KV.put("promo:summer", "active", {
expiration: Math.floor(Date.now() / 1000) + 86400, // Unix timestamp
});

When to Use KV (vs Other Storage)

StorageBest ForConsistencyFree?
Workers KVRead-heavy, globally distributed dataEventually consistent
D1Relational data, complex queriesStrong (per-region)✅ (limited)
Durable ObjectsReal-time collaboration, counters, WebSocketsStrongly consistent✅ (limited)
R2Large files, S3-compatible storageStrong💰 Paid
When NOT to Use KV

KV is not suitable for data that needs immediate consistency. If you write a value and read it immediately from a different location, you might get the old value. For strong consistency, use Durable Objects or D1.

Key Takeaways

  • Workers KV is a global key-value store optimized for read-heavy workloads.
  • Reads are fast (<10ms), writes propagate globally in ~60 seconds.
  • Free tier: 100k reads/day, 1k writes/day, 1 GB storage.
  • Support for JSON values, TTL expiration, and key listing.
  • Use KV for configuration, sessions, and cached data — not for data requiring strong consistency.

What's Next