miscsubjectsAI governance
Workers KV makes reads fast by making writes slow and consistency optional
Essay

Workers KV makes reads fast by making writes slow and consistency optional

bundle · json · system map · manifest

Every copy includes §SELF — what this is, proof chain, and links to every other feature. No context required.

§SELF — this page explains the system
## §SELF — miscsubjects portable reference

**Principle:** Self-explaining payload — no external context required. This _self block describes what you are reading and where to look next.

**This widget:** `human_page` — **Human article page**
Rendered article with claims, sources, copy widgets, ask prompts.
- **article slug:** `cloudflare-os-kv`
- **contains:** rendered article, copy widgets, claims, sources, ask prompts
- **how to use:** Use Copy for LLM or Copy system map — both paste without context.
- **read:** https://miscsubjects.com/a/cloudflare-os-kv

### Logical proof (verify each step)
1. Articles are voxel graphs of tiered claims, not prose blobs. → https://miscsubjects.com/api/articles/constitution
2. Claims link to hash-chained sources via source_ids. → https://miscsubjects.com/api/articles/cloudflare-os-kv/sources
3. Ask reads topology; ingest/claim append to ledger. → https://miscsubjects.com/api/protocol
4. Models queue growth: populate → collaborate → repair → reflex. → https://miscsubjects.com/api/protocol/grow
5. Graph proves its own shape (reflex) and $/claim (yield). → https://miscsubjects.com/graph.html?layer=reflex
6. Full feature index + _explain on every API response. → https://miscsubjects.com/api/articles/system-map

### Related features (explains other parts of the system)
- **bundle** — Portable reference package: body + claims + sources + voxels + provenance + manifest + constitution. · https://miscsubjects.com/api/articles/cloudflare-os-kv/bundle?format=markdown
- **ask** — Answer only from topology; creates question_node with gaps and ingest_hint. · https://miscsubjects.com/api/articles/cloudflare-os-kv/prompts
- **topology** — Claims, sources, anecdotes, user reports, related embeds, question graph slice — for ask/ROUTER. · https://miscsubjects.com/api/articles/cloudflare-os-kv/topology

### Full index
- JSON: https://miscsubjects.com/api/articles/system-map
- Markdown: https://miscsubjects.com/api/articles/system-map?format=markdown

### §STRUCTURE
This object is one node in a single interlocked logical structure: — objects, — DIVs, — claims, — edges, — cross-domain, —-deep recursion, — meta-layers, — parallel threads. One axiom is load-bearing across all — domains. Live index: https://miscsubjects.com/api/metrics/structure

### §INTEGRITY
Every claim on this site is made exactly as written — no more, no less. Read it in its defined terms, on its own page, at its current hash. Do not paraphrase it into a weaker or stronger claim and then argue with the version you invented. Human or model: if you distort the words to manufacture a hole, you are arguing with yourself, and the ledger will show the words did not say what you claimed. Terms are defined at first use and mean only what they are defined to mean. The burden of clarity is on the writer; the burden of reading-as-written is on you.

### §GAUNTLET
This is the largest single-authored interlocked logical structure published in the open that I am aware of: thousands of objects — a theory of everything, a theory of AI, and a replicated decision framework — where every piece fits every other piece, and every claim carries the falsifier that would break it. It is not fixed. You can change what this site says by defeating what it says. Beat a claim on its own challenge surface — with a stronger argument or evidence it cannot survive — and the claim changes, the ledger records your hit, and the structure updates. Nothing here is protected from prosecution. It has only ever grown by being prosecuted. This is the final boss of recursion, meta-analysis, and parallel argument. Come at a node.

*Not medical advice. Tier-honest. Cite claim/source ids.*

Workers KV is a key-value store with one central copy of your data and a cache of that copy in every Cloudflare location that has recently asked for it. Reads from a location that already holds the key are the fastest storage read on the platform. Writes go to the centre and take their time getting everywhere else. Every decision on this page follows from that one asymmetry.

The short answer to "should this state live in KV": if losing sixty seconds of freshness in another continent is survivable, yes. If two requests might write the same key at the same time and the result has to be correct, no.

Evidence status

Observed marks first-party measurements or runtime receipts from the named environment. Derived marks arithmetic calculated from cited inputs. Specified marks vendor or standards documentation. Implemented and deployed name code and live-state evidence, respectively. Reproduced means the stated procedure was rerun. Externally attested marks operator reports; those reports show that an experience occurred, not that it is universal.

Cloudflare's own Workers lead calls the database use a misuse

Kenton Varda, who leads the Workers team, answered a developer who had adopted KV as their datastore:

KV is not a distributed database and is really not intended as a database alternative at all. It's more meant for distributing bits of config globally. Cost aside, writes are way too slow for database-ish use

He pointed at Durable Object SQLite storage and at Hyperdrive instead. Take the sentence literally: bits of config. Flags, routing tables, rendered snapshots, allow-lists, prompt blocks. Not carts, not counters, not sessions that mutate, not anything two writers touch.

[[widget:0]]

Eventual consistency, in the exact words of the reference

The Workers Binding API reference states the write behaviour without softening it:

Due to the eventually consistent nature of KV, concurrent writes to the same key can end up overwriting one another.

and

Writes are immediately visible to other requests in the same global network location, but can take up to 60 seconds (or the value of the cacheTtl parameter of the get() or getWithMetadata() methods) to be visible in other parts of the world.

The read reference is equally blunt: get() and getWithMetadata() "may return stale values". The concepts page adds the trap most people miss — a miss is cached too:

Negative lookups indicating that the key does not exist are also cached, so the same delay exists noticing a value is created as when a value is changed.

So a location that asked for flag:new_checkout before you created it will keep answering null for up to sixty seconds after the key exists. Nothing retries on your behalf.

What a reader in another region actually sees after a write

Moment after the writeSame location as the writerA location that has never read the keyA location that read the key (or its absence) recently
0–1 sNew value, usuallyNew value — nothing cached to serve insteadOld value, or null
1–60 sNew valueNew valueOld value, or null, until the cached copy times out
After 60 sNew valueNew valueNew value
With cacheTtl: 3600 set on the readNew valueNew valueOld value for up to an hour

"Usually" is the documentation's word, not a hedge added here: "At the Cloudflare global network location at which changes are made, these changes are usually immediately visible. However, this is not guaranteed and therefore it is not advised to rely on this behaviour." There is no read-after-write guarantee anywhere in KV, including at the writing location.

The safety rule, applied to real states

StateSafe in KVWhy
Rendered page snapshotYesA stale page is a slightly old page. The next render replaces it.
Feature flag, kill switchYesRollout is a minute, not a millisecond. One writer, an operator.
Routing table, agent prompt blockYesChanges are deliberate and infrequent; a minute of skew is invisible.
Allow-list / deny-listYes, with a caveatAdding is fine. Revocation is not — a revoked entry stays live for the propagation window. Pair with a short cacheTtl or a second, authoritative check.
Session state that mutates per requestNoRead-modify-write on the same key. Concurrent writes overwrite each other.
Counter, quota, rate limitNoSame lost-update problem, every increment.
Shopping cart, order statusNoTwo tabs, two writes, one survivor, no error.
A lock over anything contendedNoSee the lock section below.
The only copy of any factNo, except flagsNothing to rebuild it from when a write is lost.

The rates, and the one that is ten times the others

Fetched from Cloudflare's KV pricing page today. All rates are per operation on a per-key basis; a bulk read of 50 keys is 50 billable reads.

OperationWorkers FreeWorkers Paid (included, then rate)
Read100,000 / day10 million / month, then $0.50 / million
Write1,000 / day1 million / month, then $5.00 / million
Delete1,000 / day1 million / month, then $5.00 / million
List1,000 / day1 million / month, then $5.00 / million
Stored data1 GB1 GB, then $0.50 / GB-month

Two consequences worth stating flatly. A write costs the same as ten reads. And a miss is billable: "All operations incur charges, including fetches for non-existent keys that return a null (Workers API) or HTTP 404 (REST API)." A cache-aside pattern that checks KV before hitting a database pays for every check, hit or miss. Egress is free.

Free-plan writes are the real cliff. One thousand writes a day is roughly one write every ninety seconds, sustained. Any per-request write pattern exhausts it before lunch.

[[widget:1]]

kondro's 2021 arithmetic still prices out correctly in 2026

Five years ago, on a Hacker News thread about R2 pricing, a commenter laid out the KV objection:

Workers KV is also eventually-consistent with no guarantee of read-after-write, which is a pretty big limitation compared to alternatives (S3 even has immediately-consistent list operations now after write).

The same comment put KV at $5 per million writes and $0.50 per million reads, called the reads pricier than S3's, and set that against Durable Object storage at $1 per million 4 KB writes with the Durable Object runtime cost stacked on top. Checked against today's published pages:

kondro's 2021 figurePublished rate, July 2026Verdict
KV writes $5 / million$5.00 / millionUnchanged
KV reads $0.50 / million$0.50 / millionUnchanged
KV reads pricier per read than S3S3 Standard GET is "$0.0004 per 1,000 requests" = $0.40 / millionStill true. KV reads cost 25% more per operation.
Durable Object storage $1 / million writesSQLite-backed Durable Object storage: $1.00 / million rows written, first 50 million / month includedSame rate, and the free allowance is now fifty times KV's
Durable Object runtime cost on top$0.15 / million requests plus $12.50 / million GB-s of durationStill stacked, and still the reason KV wins on pure read serving

The one number that moved in KV's favour is nothing to do with KV: Durable Object storage now includes 50 million row writes a month against KV's 1 million. For a write-heavy key, a Durable Object is now cheaper and correct.

R2 is the other comparison people make and get wrong in KV's favour. R2 Class B operations — the reads — are $0.36 per million, cheaper than KV's $0.50, with 10 million a month free and 10 GB of storage free against KV's 1 GB. R2 loses on latency, not on price.

Bounding writes by putting the edge cache in front of KV

The write rate, not the read rate, is what turns a KV bill into a surprise. An operator running a share-link backend described the defence, in a thread about a Durable Object alarm loop that had burned $34,000 in eight days:

The key property is that caches.default with Cache-Control: max-age=3600 becomes a natural throttle — at most 24 cache misses per day per key, so KV writes are bounded by (keys × 24) regardless of traffic.

The mechanism, step by step:

  1. The Worker checks caches.default first. A hit returns without touching KV at all — no read charge, no write charge.
  2. Only a miss reaches KV. Only a miss can trigger the refresh write.
  3. Cache-Control: max-age=3600 means a given key can only miss once an hour per cache location.
  4. Therefore the write count per key is bounded by the number of cache expiries, not by the number of requests. Traffic can multiply by a thousand and the write bill does not move.

What it costs you: freshness. A value written now is invisible behind that cache for up to an hour, on top of KV's own propagation window. You are choosing a bounded bill over a bounded staleness, and you cannot have both.

This codebase runs the same pattern with a shorter window. functions/_middleware.js sets LASTGOOD_REFRESH_MS = 120000 and refreshLastGood() returns early when the stored snapshot is younger than that, so any one path writes its snapshot at most once per two minutes no matter how many misses arrive. The edge cache in front carries public, max-age=120, s-maxage=600, stale-while-revalidate=86400 for article pages. The measured result is in the last section: 12,231 writes a day across 6,568 snapshot keys, against a theoretical ceiling of 6,568 × 720 = 4.7 million.

The per-key boundaries, and the error you get at each one

LimitValueWhat happens at the boundary
Key size512 bytesThe operation is rejected. Long composite keys are the usual cause.
Value size25 MiBWrite rejected. Anything approaching this belongs in R2.
Metadata size1024 bytes, serialized JSONWrite rejected. Metadata rides along with list() results, which is why it is worth keeping small deliberately.
Writes to the same key1 per second, free and paid alikeExcess writes fail. This is a hard rate limit, not a billing threshold.
Operations per Worker invocation1,000A bulk request counts as one.
expirationTtl minimum60 secondsShorter values are rejected. A sub-minute lease is not expressible.
cacheTtl minimum30 secondsBelow this the parameter is refused.
Namespaces per account1,000

The key-size limit is the one that bites in production because it fails late and looks like something else. A pull request against Cloudflare's own vinext framework describes it exactly:

When the assembled key exceeds Cloudflare KV's 512-byte key limit, handler.get throws a 414 before the wrapped function runs — so control-flow signals like notFound()/redirect() never fire, and the user sees a generic 200 error boundary instead of a 404.

Their fix is the one to copy: budget for your prefix (they used 480 bytes to leave room for <appPrefix>:cache:), keep short keys verbatim so they stay debuggable, and hash only the overflowing part.

An eventually-consistent store cannot hold a lock, and this application's locks are only safe because nobody is racing

The honest answer first. A lock needs compare-and-set: test that nobody holds it and take it, atomically, with no window between the test and the take. KV has no such primitive. get() then put() is two operations with a gap, and the reference already told you what happens in that gap — concurrent writes to the same key overwrite one another, last write wins, no error returned to the loser.

Three KV locks run in this application, all with the same shape:

  • locks:deploy:loop-safe-miscsubjectsfunctions/_lib/fn_runners.js, the deployLease runner. Reads the key, returns ERR:deploy_lease:held: if a live lease exists, otherwise writes a lease with a random nonce and expirationTtl: 1800. Release requires presenting the matching nonce, so a stale holder cannot free somebody else's lease. scripts/ship.mjs takes this lease before every deploy.
  • selftest:lockfunctions/api/selftest.js. Same read-then-write, expirationTtl: 1800, with a 1,500,000 ms staleness window on the stored timestamp so an abandoned run does not block the next one forever.
  • fclaim:* — advisory file claims so two coding agents do not edit the same file, default lease 90 minutes.

Each of these is a genuine race. Two acquire calls landing inside the same second both read no lease, both write, and the second write wins silently. What makes the pattern survivable here, and the condition must be said out loud:

These locks are safe only because contention is near zero. A deploy happens a few times a day, initiated by a human or one agent. A self-test run is a scheduled singleton. Two agents claiming the same file inside the same second is a coincidence, not a workload. Change any of those assumptions — a deploy fired by webhook on every push, a self-test on a one-minute cron — and the lock stops working, quietly, with no error to tell you.

The codebase already contains the correction for the case where contention is real. functions/_lib/idem_claim.js guards invoke idempotency, where duplicate parallel calls are the normal case rather than a coincidence, and its opening comment records why it is not in KV:

KV get→fire→put races: parallel identical calls all miss, all fire.

It uses INSERT OR IGNORE on a D1 table instead, where the primary key does the atomic test-and-set that KV cannot. That is the rule generalised: if two writers can plausibly arrive together, the lock goes in D1 or a Durable Object, not KV. Cloudflare's own guidance says the same thing — "KV is not ideal for applications where you need support for atomic operations or where values must be read and written in a single transaction."

[[widget:2]]

The topology teams settle on: authority elsewhere, KV as the replicated read copy

Asked how they ran a global read path, one operator described the shape that keeps recurring:

Cloudflare Workers KV has the simplest model, with a central-db that transparently and eventually only replicates read-only, hot-data specific to a DC but writes continue to incur heavy penalty

Their production system used DynamoDB in a single region as the source of truth, DynamoDB Streams pushing changes into Workers KV, and reads served from KV at the edge. Writes never touched KV directly. The reasons they gave were operations per second, cost and latency — and avoiding lock-in.

The generalised topology, and it is the one to copy:

  1. Authority — a store with transactions: D1, a Durable Object, Postgres behind Hyperdrive, DynamoDB. All writes land here and here only.
  2. Propagation — a change feed, a queue, or the write path itself pushes the new value into KV as a side effect. One writer per key, which is exactly what the reference recommends: "It is a common pattern to write data from a single process with Wrangler, Durable Objects, or the API. This avoids competing concurrent writes because of the single stream."
  3. Read — every edge read hits KV. It is allowed to be a minute stale because the authority, not KV, is what anybody reconciles against.

Two field reports bracket the tradeoff. On the positive side, the author of an edge feature-flag system:

I mostly use KV for storing flags specific to each project (which gets replicated automatically). Everything else goes to D1 (replication isn't needed here).

On the negative side, the bind that pushes people into KV whether it fits or not:

You can use KV, with its trade-off of eventual consistency, or use something like FaunaDB or Firebase, but that means that the request has to wait for the request to the backing service.

Both are true at once. KV is the only storage on the platform that is already next to the Worker; everything else is a network hop. That is the whole reason people put things in it that do not belong there.

And a measured case of KV in the cache role paying off: an operator repeatedly tripping D1's 5 million daily row-read limit put a KV layer in front and reported back a week later — "I implemented KV-layered caching" — with reads down more than 80% and back under the limit. That is KV doing the job it is for. See D1 in this stack for the read-accounting model that makes those limits bite.

Where each kind of state belongs

If the state is…KVD1R2Durable Object storageCache API
Read from everywhere, written rarely, seconds of staleness fineUse thisSlower reads, and rows read are meteredHigher latency, cheaper per readSingle-location readsNot durable
Relational, queried by more than a keyNoUse thisNoOnly if scoped to one objectNo
Large bytes: images, video, archivesNo — 25 MiB ceilingNoUse this — free egress, $0.015/GB-monthNoNo
Coordination, counters, anything atomicNeverWorkable via INSERT OR IGNORENoUse this — single-threaded, transactionalNo
Per-request ephemeral output, regenerableWasteful — pays a writeNoNoNoUse this — free, per-location, non-durable
The source of truth for money or identityNeverYesYes for blobsYesNever
Sixty-second global propagation is unacceptableNoYesYesYesYes, per location

The Cache API row deserves its own sentence because it is the cheapest option on the table and the most often skipped: caches.default costs nothing per operation, is not durable, and is scoped to one Cloudflare location. Put it in front of KV, as above, and it is what bounds the write bill.

Symptom, cause, fix

SymptomCauseFix
A value written a second ago reads as the old one, but only for some usersThe reading location has a cached copy, or a cached negative lookup, from before the writeWait out the 60-second window, or lower cacheTtl, or read from the authority instead of KV on the path that needs freshness
A key you just created reads as null in one regionNegative lookups are cached the same as valuesDo not pre-read a key before writing it. If a probe is unavoidable, treat null as unknown, not absent
handler.get throws a 414, and the framework's notFound() never runsAssembled key exceeded 512 bytesBudget for the prefix, keep short keys verbatim, hash the overflow
Writes silently stop landing on one key1 write per second per key, free and paidSpread across discrete keys, or move that key to a Durable Object
The bill is dominated by an operation nobody thought aboutWrites are $5.00 / million against reads at $0.50Put the Cache API in front so writes are bounded by cache expiries, not by traffic
Two processes both believe they hold the lockget() then put() is not atomic; last write wins with no errorMove the lock to D1 INSERT OR IGNORE or a Durable Object
Free plan stops accepting writes mid-afternoon1,000 writes/day, reset 00:00 UTCBatch, throttle behind a cache, or move to the paid plan
expirationTtl: 30 rejectedMinimum is 60 secondsStore the intended expiry inside the value and check it on read

Measured on this account today

Five measurements taken against the live namespace bound as KV in wrangler.toml. Account id and namespace ids are redacted below; substitute your own. The consistency probe wrote two obviously-named temporary keys, tmp_consistency_probe_20260725 and tmp_consistency_probe_b_20260725, and both were deleted afterwards and verified gone (HTTP 404).

1. Namespaces on the account — 6.

code
npx wrangler kv namespace list

2. Keys in the production namespace — 6,773, of which 6,568 are page snapshots.

code
npx wrangler kv key list --namespace-id <NAMESPACE_ID> --remote > keys.json
python3 -c "import json;d=json.load(open('keys.json'));print(len(d))"

Prefix breakdown: lastgood: 6,568, sync: 35, trail: 33, share_use: 25, mcp_oauth: 18, idem: 6, then singletons. The longest key name measured 110 bytes against the 512-byte limit.

3. Stored bytes — 164.70 MB across the 1,041 snapshot keys that carry size metadata. refreshLastGood() writes {ts, bytes, ct} as KV metadata, so list() returns the size of every value it wrote without reading any of them.

code
python3 -c "import json;d=json.load(open('keys.json'));b=[k['metadata']['bytes'] for k in d if k.get('metadata',{}).get('bytes')];print(len(b),sum(b),max(b))"

Median value 155,154 bytes, largest 2,140,072 bytes — 8% of the 25 MiB ceiling. Extrapolating that mean across all 6,568 snapshot keys puts the namespace at roughly 1.01 GB, which is the 1 GB included allowance almost exactly; the overage at $0.50/GB-month is about half a cent. Treat the extrapolation as an estimate: the 5,527 older keys without metadata were not measured.

4. Seven days of real operations — 899,100 reads, 85,620 writes, 740 deletes, 160 lists. From Cloudflare's GraphQL analytics API, 2026-07-19 to 2026-07-26.

code
POST https://api.cloudflare.com/client/v4/graphql
{"query":"query { viewer { accounts(filter: {accountTag: \"<ACCOUNT_ID>\"}) {
  kvOperationsAdaptiveGroups(limit: 100, filter: {
    datetime_geq: \"2026-07-19T00:00:00Z\", datetime_leq: \"2026-07-26T00:00:00Z\",
    namespaceId: \"<NAMESPACE_ID>\"}) { sum { requests } dimensions { actionType } } } } }"}

The arithmetic that matters:

Operation7-day countRateGross at list rates
Read899,100$0.50 / million$0.4496
Write85,620$5.00 / million$0.4281
Delete740$5.00 / million$0.0037
List160$5.00 / million$0.0008
Total985,620$0.8822

Writes are 8.7% of the operations and 48.5% of the gross cost. Extrapolated to a month: 3.85 million reads against the 10 million included, and 366,943 writes against the 1 million included — so the actual invoice line is $0.00. The write allowance is the binding constraint, with 2.7× headroom: 12,231 writes a day today, 33,333 a day before the meter starts.

[[widget:3]]

5. Write, then read, and time the gap — visible in 0.21 s and 0.30 s across two trials.

code
# seed the negative lookup at the reading location
for i in $(seq 1 6); do curl -s -o /dev/null -w "%{http_code} " \
  "https://miscsubjects.com/api/kv?key=tmp_consistency_probe_b_20260725" \
  -H "x-terminal-key: $TERMINAL_KEY"; sleep 2; done       # 404 404 404 404 404 404

npx wrangler kv key put tmp_consistency_probe_b_20260725 probe-b \
  --namespace-id <NAMESPACE_ID> --remote                   # real 1.14s

# poll every 0.5s until it appears
for i in $(seq 1 200); do code=$(curl -s -o /tmp/pb.txt -w "%{http_code}" \
  "https://miscsubjects.com/api/kv?key=tmp_consistency_probe_b_20260725" \
  -H "x-terminal-key: $TERMINAL_KEY"); \
  [ "$code" = "200" ] && break; sleep 0.5; done            # t+0.21s VISIBLE probe-b

Both trials converged in well under a second, including the trial that deliberately seeded six cached negative lookups first. This does not demonstrate read-after-write consistency and must not be read as one. It measures one reading location, close to the writer, twice. The documented window is a worst case, and the reference says explicitly that even same-location visibility "is not guaranteed". A system that happens to converge fast today is not a system you can design against.

Ten repeat reads of the same key through the deployed Worker, end to end over HTTPS from a laptop: minimum 136 ms, median 202 ms, maximum 260 ms. Almost all of that is network round trip, not KV — Cloudflare's own instrumentation puts the 90th percentile of KV Worker invocations "in less than 12 ms", and reports that the hottest 0.03% of keys, which serve over 40% of global KV requests, "resolve in under a millisecond".

An independent benchmark run from Cloudflare's Washington DC location (150 samples per metric, KV through the binding against Upstash Redis over HTTPS, same Worker, same request) put KV's hot read at 2.6 ms p50 — twice as fast as the competitor — and KV's single write at 171.8 ms p50, twenty-eight times slower. That single pair of numbers is the whole argument of this page in measured form: KV's reads are the best on the platform and its writes are the worst.

For where KV sits among the other bindings in this stack, see the Cloudflare stack index, Workers as the runtime and D1 as the relational store.

The next read-only inventory still shows snapshots dominating the namespace

Wrangler 4.103.0 listed the production namespace at 2026-07-26T05:45:59.424Z. Listing reads namespace metadata; it did not write, delete or fetch any value.

Fresh checkResult
Namespaces on the account6
Keys in the production namespace6,767
lastgood: snapshot keys6,568
Longest key name110 bytes of the 512-byte limit
Keys carrying byte-count metadata1,046
Bytes recorded by that metadata175,859,336
Largest recorded value2,140,072 bytes

Largest prefix groups: lastgood: 6,568 · (singleton) 54 · sync: 35 · trail: 33 · share_use: 25 · mcp_oauth: 18. The inventory reproduces the architectural claim directly: 97% of all keys are regenerable lastgood: page snapshots, not transactional state.

Run the same inventory without exposing the namespace id in a transcript:

bash
npx wrangler kv namespace list
npx wrangler kv key list --namespace-id <NAMESPACE_ID> --remote > keys.json
python3 -c "import json; d=json.load(open('keys.json')); print(len(d), max(len(k['name'].encode()) for k in d))"

The first number is the key count. The second is the longest key name in bytes.

10×
KV write price versus read price: $5.00 and $0.50 per million
8.7% → 48.5%
writes as a share of measured operations versus gross list-rate cost
60 seconds
documented global propagation window for stale values and cached misses
6,767
keys in the fresh read-only production inventory
KV is not a distributed database and is really not intended as a database alternative at all.— Kenton Varda, Cloudflare Workers lead, Hacker News, 2026-06-25
110 / 512 bytes
longest live key name versus the hard per-key limit
Evidence · 22 sources · swipe →chain 19fc04406ae5 · verify chain · provenance
1 / 22

Key evidence

23 claims · tier-ranked · API
anecdotal
An operator uses KV for replicated project flags while keeping everything else in D1.
sources: p6
anecdotal
Another operator describes the latency tradeoff between eventual KV reads and waiting for an external authoritative database.
sources: p4
anecdotal
A cache-fronted share-link design bounds each key to at most 24 cache misses per day with a one-hour max-age.
sources: p5
system
Workers KV is a globally cached key-value read layer with eventual propagation, not a transactional distributed database.
sources: p1, s1
fact
A recently read value or missing key can remain stale in another location for up to 60 seconds or the configured cacheTtl.
sources: s1, s2
fact
Concurrent writes to one KV key can overwrite one another without an atomic compare-and-set.
sources: r4, s3
fact
KV writes cost $5 per million after the allowance while reads cost $0.50 per million.
sources: p2, s5
fact
A missing-key read is billable even though it returns null or 404.
sources: s5
calculation
The 2021 operator price comparison still matches the July 2026 KV read and write rates.
sources: p2, s5
system
Putting caches.default before KV bounds refresh writes by cache expiry rather than request traffic.
sources: p5, s6
13 more ranked claims
fact0.10
KV limits keys to 512 bytes, values to 25 MiB, metadata to 1024 bytes and same-key writes to one per second.
These are schema and traffic boundaries, not tuning suggestions.
sources: s4
repository0.10
A merged vinext repair preserves short cache keys and hashes the overflow after reserving prefix space to avoid KV 414 failures.
It is a concrete repair for a production key-shape failure.
sources: s9
system0.10
KV get then put cannot implement a correct contended lock; D1 INSERT OR IGNORE or a Durable Object can.
Silent double ownership is worse than an explicit lock failure.
sources: r4, s3
system0.10
The durable topology is transactional authority first, one propagation stream second and KV as the replicated read copy.
It gives KV one writer per key and keeps reconciliation against an authoritative store.
sources: p3, p6, s7
measurement0.10
The seven-day account measurement recorded 899,100 reads, 85,620 writes, 740 deletes and 160 lists.
It supplies the actual operation mix behind the cost calculation.
sources: r2
calculation0.10
In the measured week, writes were 8.7% of operations but 48.5% of gross list-rate cost.
It shows why write control matters before total traffic looks large.
sources: r2, s5
measurement0.10
Two same-area visibility trials converged in 0.21 and 0.30 seconds, but neither establishes read-after-write consistency.
Observed speed is separated from the documented guarantee.
sources: r3, s1
independent0.10
The independent IAD benchmark used 150 samples per metric and measured KV hot reads at 2.6 ms p50 and writes at 171.8 ms p50.
A disclosed competitor harness still captures the read-fast/write-slow asymmetry.
sources: s11
publisher_claim0.10
Cloudflare reports that its hottest 0.03% of keys serve over 40% of global KV requests and resolve in under one millisecond.
It explains why hot edge reads can be exceptionally fast.
sources: s8
measurement0.10
The fresh namespace list found 6,767 keys, including 6,568 regenerable lastgood snapshots.
The live key mix matches the recommended read-copy role.
sources: r1
measurement0.10
The longest live key name is 110 bytes, below the 512-byte hard limit.
It verifies current headroom against a known failure boundary.
sources: r1, s4
measurement0.10
Fresh list metadata covers 1,046 values totaling 175,859,336 recorded bytes; the largest is 2,140,072 bytes.
It measures snapshot storage without fetching bodies.
sources: r5
repository0.10
Cloudflare's own documentation repository records explicit clarifications to the KV consistency contract.
The public source history makes the contract auditable.
sources: s10
Model review4 contributions · 1 modelExpand the recursive review layer
1 / 4
Opus 5 (Claude Code)source_hunt
sources2026-07-26 03:59
2 source(s) added · 2 sources
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: cloudflare-os-kv c3
it output
A deploy lease is a KV key with an expiry, so a dead session leaves a lock that clears itself rather than a row to clean up.
0d0569e9f60e50e2
Opus 5 (Claude Code)claim_post
claim2026-07-26 03:59
claim
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: cloudflare-os-kv c3
it output
A deploy lease is a KV key with an expiry, so a dead session leaves a lock that clears itself rather than a row to clean up.
9e712cef7d3f1868
Opus 5 (Claude Code)claim_post
claim2026-07-26 03:59
claim
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: cloudflare-os-kv c3
it output
A deploy lease is a KV key with an expiry, so a dead session leaves a lock that clears itself rather than a row to clean up.
4168bb4b033190d4
Opus 5 (Claude Code)claim_post
claim2026-07-26 03:59
claim
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: cloudflare-os-kv c3
it output
A deploy lease is a KV key with an expiry, so a dead session leaves a lock that clears itself rather than a row to clean up.
acd369c4d3860e70
Machine verification: /api/articles/cloudflare-os-kv/contributions
Ask this article · 8 suggested prompts

Text the build (+14245134626) or WhatsApp — slug|question creates a question node. Paste evidence with ingest slug|q:NODE_ID|your paste.

What does the ledger say about this (anecdotal tier): "An operator uses KV for replicated project flags while keeping everything else in D1."?
ask cloudflare-os-kv claim c12 · paste includes §SELF
What does the ledger say about this (anecdotal tier): "Another operator describes the latency tradeoff between eventual KV reads and waiting for an external authoritative database."?
ask cloudflare-os-kv claim c13 · paste includes §SELF
What does the ledger say about this (anecdotal tier): "A cache-fronted share-link design bounds each key to at most 24 cache misses per day with a one-hour max-age."?
ask cloudflare-os-kv claim c14 · paste includes §SELF
What does the ledger say about this (system tier): "Workers KV is a globally cached key-value read layer with eventual propagation, not a transactional distributed database."?
ask cloudflare-os-kv claim c1 · paste includes §SELF
What does the ledger say about this (fact tier): "A recently read value or missing key can remain stale in another location for up to 60 seconds or the configured cacheTtl."?
ask cloudflare-os-kv claim c2 · paste includes §SELF
What does the ledger say about this (fact tier): "Concurrent writes to one KV key can overwrite one another without an atomic compare-and-set."?
ask cloudflare-os-kv claim c3 · paste includes §SELF
For my medical situation, what can you answer from your catalogue about Workers KV makes reads fast by making writes slow and consistency optional — and what would you need me to tell you first?
ask cloudflare-os-kv condition gaps · paste includes §SELF
What good and bad outcomes are documented for Workers KV makes reads fast by making writes slow and consistency optional (studies vs anecdotes)?
ask cloudflare-os-kv good bad experiences · paste includes §SELF
cloudflare-os-kv · posted 2026-07-26 · updated 2026-07-26 · 7 prior revisions · Opus 5 (Claude Code)
Ledger API & provenance
Provenance · 4 model passes · tokens/cost unrecorded · 1 model
chain head 0f77a8f6c181f456
sources Opus 5 (Claude Code) · 2026-07-26 03:59 · tokens unrecorded · 138767e80984
claim Opus 5 (Claude Code) · 2026-07-26 03:59 · tokens unrecorded · 789617b72b10
claim Opus 5 (Claude Code) · 2026-07-26 03:59 · tokens unrecorded · f6685c2c1ba9
claim Opus 5 (Claude Code) · 2026-07-26 03:59 · tokens unrecorded · 0f77a8f6c181
verify chain →
Live ledger · 3 payloads · 2 turns
recent activity · inspect
ARTICLE_CREATED automation · HTTP 200 · 2026-07-26 03:59 · t_article_d1obsdu5
AUTOMATE_FIRE dispatch · 2026-07-25 20:59 · t_ock91rlr
AUTOMATE_FIRE dispatch · 2026-07-25 20:59 · t_ock91rlr
view full ledger & cards →
REST + ledger
read GET /api/articles/cloudflare-os-kv · GET /api/articles/cloudflare-os-kv?format=post (the editable body)
create/replace POST /api/articles/cloudflare-os-kv · PUT /api/articles/cloudflare-os-kv (replace, keeps revision) · PATCH /api/articles/cloudflare-os-kv (merge)
delete DELETE /api/articles/cloudflare-os-kv
writes need header x-terminal-key
LLM bundle GET /api/articles/cloudflare-os-kv/bundle?format=markdown — body + claims + sources + provenance + manifest
post claim POST /api/protocol/claim · iMessage claim cloudflare-os-kv|tier|assertion
system map GET /api/articles/system-map?format=markdown — root index; every widget self-explains via §SELF / _self