In the previous article in this series we showed how Cloudflare Workers run code in hundreds of locations at once. But a question quickly arises: if an isolate remembers nothing between requests, where do you keep data? Cloudflare’s simplest answer is Workers KV, a globally replicated key-value store designed for one specific thing: lightning-fast reads all over the world. In this article we explain how KV works under the hood, when it is spot on and when it is a trap, and we show three practical usage patterns with code.
Cloudflare KV: a lightning-fast data store at the network edge
03.09.2026 | Author: Marcin Wiercioch
What is Workers KV?
KV is a key → value store: under a text key (up to 512 bytes) you store a value, which can be text, JSON or binary data up to 25 MiB. There are no tables, relations or queries, just four operations: get, put, delete and list. This simplicity is the price we pay for something exceptional: data is automatically replicated across the Cloudflare network and read from the location closest to the user, often in under a millisecond for “hot” keys.
The most important thing: the consistency model
KV is eventually consistent. A write is immediately visible in the location that accepted it, but it takes up to about 60 seconds to propagate to the other points of the network. What does this mean in practice?
- If a user in Tokyo writes a value, a user in Warsaw may still see the old one for a moment.
- KV is not suitable for counters, carts, locks or anything that requires “read and immediately update”: two parallel writes to the same key end with the last one winning.
- The write limit is 1 per second per key, which is a deliberate signal from the designers: KV is for reading, not writing.
A good rule of thumb: KV fits where you write data rarely and read it often and everywhere. Configuration, feature flags, tokens, cache, redirects, content: yes. Session state, a vote counter, store inventory: no (that is what Durable Objects or D1 are for, which we mention at the end).
Setting it up in a project
We create a namespace with Wrangler and attach it to the Worker as a binding:
npx wrangler kv namespace create CONFIG
Wrangler prints an identifier that we add to the project configuration (wrangler.jsonc):
{
"kv_namespaces": [
{ "binding": "CONFIG", "id": "5f31...c0de" }
]
}
From then on, the env.CONFIG object with the store’s methods is available in the Worker code. It is worth knowing that values can also be written from the console and CI: npx wrangler kv key put --binding CONFIG "key" "value".
Pattern 1: caching responses from a slow API
The most common case in our projects: an external API is slow or has strict limits, and the data changes rarely. KV acts as a global cache with freshness control:
export default {
async fetch(request, env) {
const key = "exchange-rates";
const cached = await env.CONFIG.get(key, { type: "json" });
if (cached) {
return Response.json(cached);
}
const res = await fetch("https://api.nbp.pl/api/exchangerates/tables/A?format=json");
const data = await res.json();
await env.CONFIG.put(key, JSON.stringify(data), { expirationTtl: 3600 });
return Response.json(data);
}
};
The expirationTtl parameter (in seconds) makes the entry disappear by itself after an hour, so we do not have to manage invalidation. An extra trick: the cacheTtl option on reads lets you shorten the path even further for very hot keys.
Pattern 2: feature flags and configuration without a deploy
Want to switch on a promotion banner at midnight on Saturday, or turn off an experimental feature without a deployment? Keep the flags in KV:
export default {
async fetch(request, env) {
const flags = await env.CONFIG.get("feature-flags", { type: "json" }) || {};
const html = await fetch(request).then(r => r.text());
let output = html;
if (flags.promoBanner) {
output = output.replace("<!-- baner -->", '<div class="promo">Promocja weekendowa!</div>');
}
return new Response(output, { headers: { "content-type": "text/html; charset=utf-8" } });
}
};
Changing a flag is a single write to KV: no builds, no deploy, no cache clearing. Within a minute the whole world sees the new value. The same approach works great for a redirect map during migrations: the key is the old URL, the value is the new one.
Pattern 3: metadata and listing
Each entry can have up to 1,024 bytes of metadata, which are returned when listing, without fetching the value. This is useful, for example, for an admin panel showing the contents of the cache:
await env.CONFIG.put("raport-2026-10", content, {
metadata: { author: "okinet", size: content.length }
});
const list = await env.CONFIG.list({ prefix: "raport-" });
// list.keys -> [{ name, expiration, metadata }, ...]
Key prefixes work like directories, so it is worth naming keys hierarchically from the start (cache:products:123), because list filters by prefix only.
Limits and pricing
- keys up to 512 B, values up to 25 MiB, metadata up to 1 KiB,
- 1 write per second per key (writes to different keys are unlimited),
- free plan: 100,000 reads and 1,000 writes per day, 1 GB of data,
- paid plan: 10 million reads included, then fractions of a dollar per million operations.
KV, D1 or Durable Objects?
Cloudflare has three data stores, and each serves a different purpose. KV: rare writes, massive global reads, eventual consistency. D1: full SQL (SQLite), relations and queries when you need structure. Durable Objects: strong consistency and coordination: counters, queues, games, anything where the order of operations matters. A healthy project often combines two of them: configuration in KV, transactional data in D1.
Summary
Workers KV is a tool with a narrow but superbly executed specialisation: configuration data and cache available in milliseconds all over the world, without maintaining any infrastructure. You just need to remember its nature: it is eventually consistent and does not like frequent writes. In the next article of the series we look at Cloudflare R2, object storage with no transfer fees, ideal among other things for WordPress media. And if you want to talk about edge computing in your project, we are here to help.



