Workers KV -- Key-Value Storage at the Edge
In this tutorial, you'll learn about Workers KV. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Cloudflare Workers KV is a globally distributed key-value store that replicates data across Cloudflare's edge network, giving your Workers access to persistent storage with read latencies under 10 milliseconds from any location worldwide.
Why Workers KV Matters
Traditional databases place your data in a single region, forcing remote users to wait for round trips across continents. Workers KV flips this model by replicating every key-value pair to all 330+ Cloudflare data centers. Reads are served from the nearest edge location, while writes propagate globally within seconds. This architecture powers configuration storage, A/B testing flags, static asset serving, and session data for Serverless applications built with Cloudflare. Unlike traditional REST APIs that require connection pooling and query Parsing, KV offers a simple get/set/delete interface designed for edge workloads.
Real-world use: A documentation site stores translated content in Workers KV with language-based keys. A Japanese user in Tokyo reads docs/ja/welcome from the Tokyo edge node in under 5ms, while a German user reads docs/de/welcome from Frankfurt with the same speed -- both without hitting a central database.
KV Storage Architecture
flowchart LR
W[Worker] --> KV[Workers KV]
KV --> R[Read from nearest edge]
W --> P[Write/Put]
P --> Prop[Global propagation]
Prop --> E1[Edge EU]
Prop --> E2[Edge US]
Prop --> E3[Edge Asia]
Prop --> E4[Edge Oceania]
style KV fill:#f90,color:#fff
style Prop fill:#f90,color:#fff
Creating and Binding a KV Namespace
Before using KV, create a namespace and bind it to your Worker in wrangler.toml.
wrangler kv:namespace create MY_KV
# Creates namespace with ID: abc123def
# wrangler.toml
name = "kv-worker"
main = "src/index.js"
[[kv_namespaces]]
binding = "MY_KV"
id = "abc123def"
export default {
async fetch(request, env) {
await env.MY_KV.put('greeting', 'Hello from Workers KV!');
const value = await env.MY_KV.get('greeting');
return new Response(value, {
headers: { 'Content-Type': 'text/plain' }
});
}
}
Expected output: The Worker writes the string Hello from Workers KV! to the KV namespace and then reads it back, returning it as the HTTP response. This demonstrates the fundamental put-get cycle.
Reading Values with Type Options
KV returns values as strings by default, but you can request different types.
export default {
async fetch(request, env) {
await env.MY_KV.put('counter', '42');
await env.MY_KV.put('config', JSON.stringify({ theme: 'dark', lang: 'en' }));
const str = await env.MY_KV.get('counter');
const num = await env.MY_KV.get('counter', { type: 'text' });
const config = await env.MY_KV.get('config', { type: 'json' });
return new Response(JSON.stringify({
string: str,
numberValue: num,
parsedConfig: config
}), {
headers: { 'Content-Type': 'application/json' }
});
}
}
Expected output: str and num both return "42" as text. config is auto-parsed as JSON and returns {"theme": "dark", "lang": "en"} as a JavaScript object. The json type throws if the stored value is not valid JSON.
Listing Keys with Prefixes
You can list keys matching a prefix, useful for directory-style structures.
export default {
async fetch(request, env) {
await env.MY_KV.put('users/alice/name', 'Alice');
await env.MY_KV.put('users/alice/email', 'alice@example.com');
await env.MY_KV.put('users/bob/name', 'Bob');
await env.MY_KV.put('users/bob/email', 'bob@example.com');
const userList = await env.MY_KV.list({ prefix: 'users/' });
return new Response(JSON.stringify({
keys: userList.keys.map(k => k.name),
count: userList.keys.length
}), {
headers: { 'Content-Type': 'application/json' }
});
}
}
Expected output: Returns {"keys": ["users/alice/name", "users/alice/email", "users/bob/name", "users/bob/email"], "count": 4}. The list method supports pagination with cursor and limit parameters for large namespaces.
Common Errors
| Error | Cause | Fix |
|---|---|---|
Namespace not found |
Binding name does not match wrangler.toml | Verify the binding name in [[kv_namespaces]] matches the Worker code |
KV put value exceeds limit |
Value larger than 25MB | Split large data into chunks or use R2 object storage |
Key not found |
Reading a key that does not exist | Check that the key was written and propagated (eventual consistency) |
Operation timed out |
Network issue during KV operation | Retry with exponential backoff; ensure the namespace ID is correct |
Cannot write to KV |
Free plan daily write limit exceeded | Upgrade to a paid plan or wait for the daily limit to reset |
Practice Questions
- What type of consistency does Workers KV provide and why is it designed this way?
- How do you bind a KV namespace to a Worker in
wrangler.toml? - What happens when you use
{ type: 'json' }on a value that is not valid JSON?
FAQ
Summary
Workers KV gives your Serverless applications globally replicated key-value storage with single-millisecond reads from 330+ edge locations. The simple get/put/list/delete interface handles configuration, content, session data, and feature flags without connection pools or query languages. This technology powers Doda Browser's per-user privacy settings and Durga Antivirus Pro's threat signature distribution across global edge nodes. Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro -- security-first tools for the modern web.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro