Key-value storage (KV)
KV provides storage outside an individual worker invocation. The SDK describes it as shared across worker instances for the same site. It supports byte values, UTF-8 text, and atomic counters, making it useful for small configuration values and temporary state across requests.
KV entries can be evicted. Worker code must handle a missing value, and KV should not be the only copy of data that must be retained. Sharing across invocations does not establish a guarantee of durability across restarts or replication across VIP Edge locations.
Byte and text values
Byte values and counters occupy the same keyspace. A key holds a single type at a time. Prefix keys by purpose, such as routing:label or metrics:requests, to reduce accidental collisions.
| Method | Behavior |
|---|---|
| KV.get(key) | Returns a Uint8Array, or null for an absent key or a counter key. |
| KV.set(key, value) | Stores bytes; replaces any existing value, including a counter. |
| KV.getText(key) | Reads bytes as UTF-8 text; returns null for an absent key or a counter key. |
| KV.setText(key, value) | Encodes text as UTF-8 and stores it as bytes. |
| KV.del(key) | Deletes either type; an absent key requires no action. |
An empty value is different from a missing value. KV.get() returns a zero-length array for stored empty bytes, and KV.getText() returns an empty string for stored empty text. Check explicitly for null when applying a fallback.
Atomic counters
| Method | Behavior |
|---|---|
| KV.counterGet(key) | Reads a signed 64-bit counter; returns 0 if absent. |
| KV.counterSet(key, value) | Sets a counter to an absolute value. |
| KV.incr(key, delta) | Atomically adds delta and returns the new value; delta defaults to 1. |
KV.incr() initializes an absent counter to zero before adding. A negative delta decrements it. Use this operation for concurrent increments rather than separate read and write calls.
Counter operations throw when the key contains bytes. Conversely, storing bytes at a counter key replaces the counter. Keep text and counter keys distinct.
Example: a label and a request counter
This standalone worker reads a text label, supplies a default when it is absent, and increments a separate counter. It adds both values to request headers for subsequent request processing. It does not expose an HTTP endpoint for writing arbitrary KV data.
import { KV, Request, onClientRequest } from "@automattic/vip-edge-workers-sdk";
export {
alloc,
on_client_request,
} from "@automattic/vip-edge-workers-sdk/assembly/index";
onClientRequest((request: Request): void => {
const storedLabel = KV.getText("example:label");
const label = storedLabel !== null ? storedLabel : "edge";
if (storedLabel === null) {
KV.setText("example:label", label);
}
request.headers.set("x-edge-label", label);
request.headers.set("x-edge-count", KV.incr("example:requests").toString());
});The counter illustrates shared state, not durable traffic accounting. Eviction can reset its value, and a cached response does not require the request to reach the origin.
Limits and lifetime
| Property | SDK-documented behavior |
|---|---|
| Key size | Maximum 64 bytes after UTF-8 encoding. |
| Byte/text value size | Maximum 10 KiB; multibyte text counts by encoded size. |
| Counter type | Signed 64-bit integer. |
| Eviction | Site-wide least recently used (LRU) eviction can remove entries. |
| Evicted counter | Reads as zero; a later increment starts from zero. |
The SDK does not expose key enumeration, transactions, or a per-entry time-to-live (TTL) option. The documented CLI commands manage worker deployments, not KV records. Do not assume an origin database, WordPress object cache, or another storage service shares this keyspace.
The SDK KV reference describes the storage interface. Applications needing durable records should retain those records in an appropriate persistent store and handle KV misses explicitly.
Last updated: September 22, 2026