Anything Advertising

KV namespaces

Small values your code reads on every request, without a database call.

A KV namespace is a key-value store that belongs to your account, not to a worker. Create one from Resources → Storage → KV namespaces and it exists immediately, even if you never deploy a worker. A worker uses a namespace only after you bind it in the worker's Settings tab. The console lists every namespace with its keys, storage, operations, and estimated cost, and each namespace has a page with keys, usage, limits, and import/export.

The console

The namespace list shows keys and storage against your limits, this month's reads, writes, deletes, and lists, and the estimated cost. Select a namespace to open its key browser.

On a namespace page you can:

  • add an entry from the header, or open one by selecting its row;
  • edit the value, expiration, and metadata in the side drawer;
  • search keys, choose 50–500 rows per page, and page through results;
  • download the namespace as JSON or import a JSON file from Settings;
  • see which workers are bound and watch usage in Settings;
  • delete every key, or delete the namespace itself.

Deleting a namespace removes its keys and operation history and unbinds it from every worker. Deleting a worker does not delete the namespace.

Bind a namespace to workers

Open a worker and choose Settings. In the KV namespaces section, pick a namespace and give it an alias. The alias is the name worker code uses, and the default is KV. The same namespace can be bound to several workers, each with its own alias.

  • Bind one namespace as KV to use env.KV.
  • Bind another as CACHE to use env.CACHE.
  • A worker with no KV binding has no env.KV; guard code that needs it or bind a namespace first.

Binding or unbinding restarts the worker so the new aliases appear. A namespace's keys and billing do not change when you bind or unbind it.

Use it in a worker

The binding is the alias, for example env.KV, and every call returns a promise.

export default {
  async fetch(request, env) {
    if (!env.KV) {
      return new Response("No KV namespace is bound as KV", { status: 503 });
    }
    const config = await env.KV.get("site.config", "json");
    const visits = (await env.KV.get("visits")) || "0";
    await env.KV.put("visits", String(Number(visits) + 1));
    return Response.json({ theme: config?.theme, visits });
  },
};

API

CallDoes
env.KV.get(key, type)Reads a value. Returns null when the key is missing or expired. type is "text" (default), "json", or "arrayBuffer".
env.KV.getWithMetadata(key, type)Returns { value, metadata }.
env.KV.put(key, value, options)Writes a value. Set { expirationTtl } in seconds, { expiration } as a Unix timestamp, and { metadata } as a JSON object.
env.KV.delete(key)Deletes a key. Deleting a missing key is not an error.
env.KV.list({ prefix, limit, cursor })Lists keys under a prefix, up to 1,000 per page. Returns { keys, truncated, cursor }; each key has key, metadata, and expiration.

Values can be strings, numbers, booleans, arrays, or objects passed to put; non-strings are stored as JSON. Use get(key, "json") to parse them. Keys are case-sensitive, and listing is ordered by key so a cursor stays stable while paging.

TTL and metadata

A value can expire on its own, and metadata travels with the key without being part of the value.

// A session that disappears after an hour.
await env.KV.put(
  `session:${sessionId}`,
  JSON.stringify({ userId, role: "member" }),
  { expirationTtl: 3600, metadata: { userId } },
);

const session = await env.KV.get(`session:${sessionId}`, "json");
const { value, metadata } = await env.KV.getWithMetadata(
  `session:${sessionId}`,
  "json",
);

// Page through feature flags.
let cursor;
do {
  const page = await env.KV.list({ prefix: "flag.", limit: 100, cursor });
  for (const item of page.keys) console.log(item.key, item.metadata);
  cursor = page.cursor;
} while (cursor);

Reads and writes

Reads are served from the node that runs the worker, so a request never waits on the console or the database. A write goes to the app and updates that node's snapshot before the call returns, so a read after a write on the same node sees the new value. Other nodes pick the change up on their next sync, about every five seconds. TTLs use the same clock everywhere, and an expired key reads as null.

Import and export

Export downloads the whole namespace as JSON, including metadata and expiry. Import accepts that file (up to 8 MB), an object of key/value pairs, or a list of entries. An import is all-or-nothing: if any key is invalid, no keys are written. Importing a key that already exists replaces it.

Billing

Stored bytes are billed at $0.50 per GB-month. Operations are billed per million: reads $0.50, writes and deletes $5.00, and lists $5.00. Storage accrues continuously like object storage; operations are counted per namespace per day. Deleted or expired bytes stop counting toward storage. Keys in a namespace keep accruing storage whether or not a worker is bound or running. The operator can change these rates. The namespace page shows the current month's usage and the Billing page includes the KV share.

Limits

LimitValue
Namespaces per member10 by default
Keys per namespace1,000 by default
Total value bytes per namespace4 MiB by default
One value64 KiB
Key1–512 bytes, no control characters
Metadata2 KiB JSON object
TTL60 seconds to 365 days, or no expiry
Writes100 per second per namespace
List page1,000 keys
Import file8 MB

The key and storage limits above are the defaults and apply to each namespace. If you need more, open Cloud Settings → Limits, choose KV limit → Manage limit, and request a higher allowance. An admin reviews the request; approved limits apply to every namespace you own.

Security

Values are encrypted at rest with a key bound to the namespace and key name. A worker can read only namespaces bound to it, and the console never exposes values in shared caches. The runtime receives decrypted values on the worker node, not in the browser. Use Workers environment variables for credentials that should be injected as env.NAME; KV is for values that change at runtime.