env.<BINDING> (a KvNamespace) is the in-function handle to a KV namespace. It’s a thin, pre-authenticated wrapper over the KV REST API — the runtime injects the credential, so your code holds no API key.
interface KvNamespace {
get(key: string, options?: KvGetTextOptions): Promise<string | null>;
get<T>(key: string, options: KvGetJsonOptions): Promise<T | null>;
put(key: string, value: string, options?: KvPutOptions): Promise<void>;
delete(key: string): Promise<void>;
list(options?: KvListOptions): Promise<KvListResult>;
}
Key behaviors:
- Values are opaque bytes —
put stores the string you pass verbatim (no base64, no envelope); get returns it byte-for-byte.
- Missing keys read as
null — get resolves to null for a key that doesn’t exist, not an error.
delete is idempotent — deleting a missing key succeeds.
- Read-your-writes — a read after a successful
put from the same location reflects it. See Consistency.
- Errors throw — a non-2xx from the store (other than the
404→null on get) rejects the promise with an Error describing the operation and status.
get(key, options?)
Read a value. Two overloads, selected by options.type:
interface KvGetTextOptions { type?: "text" } // default
interface KvGetJsonOptions { type: "json" } // JSON.parse the stored value
// Text (default) -> string | null
const raw = await env.MY_KV.get("user/123");
// JSON -> T | null (JSON.parse applied; an empty stored value yields null)
const user = await env.MY_KV.get<{ name: string }>("user/123", { type: "json" });
Returns null if the key does not exist. With { type: "json" }, a malformed stored value throws from JSON.parse.
put(key, value, options?)
Write a value. value is a string, stored verbatim. Resolves once the write is acknowledged.
interface KvPutOptions {
expirationTtl?: number; // seconds
metadata?: unknown;
}
await env.MY_KV.put("user/123", JSON.stringify({ name: "Alice" }));
expirationTtl and metadata are accepted but not yet applied — they exist on the type so code that sets them keeps compiling, but the runtime currently ignores them. KV does support server-side TTL over REST (?ttl_secs=) and the CLI (--ttl); it’s only this binding option that isn’t wired yet. For expiry from the binding today, use the application-level pattern.
delete(key)
Remove a key. Idempotent — deleting a missing key resolves normally.
await env.MY_KV.delete("user/123");
list(options?)
Enumerate keys (names only — list does not return values).
interface KvListOptions {
prefix?: string;
limit?: number;
cursor?: string; // from a previous result's `cursor`
}
interface KvListResult {
keys: KvKeyInfo[];
list_complete: boolean;
cursor?: string; // present when list_complete is false
}
interface KvKeyInfo {
name: string;
metadata?: unknown;
}
list() requires @telnyx/edge-runtime ≥ 0.2.1. On 0.2.0 it throws Unexpected KV list response shape, because that release’s parser predates the current API list format.
KvKeyInfo.metadata is reserved for forward compatibility — KV has no per-key metadata today, so it is never populated. (The underlying REST list returns size_bytes and updated_at per key, which this binding does not currently surface.)
- Overview — the KV Runtime API surface at a glance
- Quick Start — declare the binding and generate types
- REST API — the same operations over HTTP