Skip to main content
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 bytesput stores the string you pass verbatim (no base64, no envelope); get returns it byte-for-byte.
  • Missing keys read as nullget 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 404null 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 until the key expires server-side
  /** @deprecated Not supported by the API. Accepted but ignored. */
  metadata?: unknown;
}
await env.MY_KV.put("user/123", JSON.stringify({ name: "Alice" }));

// Expire automatically after one hour
await env.MY_KV.put("session/abc", token, { expirationTtl: 3600 });
expirationTtl maps to the REST API’s ?ttl_secs= parameter: the key is deleted server-side roughly that many seconds after the write. The value is floored to a whole number of seconds; anything below 1 is not sent — the write succeeds without a TTL. See Key Expiration.
expirationTtl requires @telnyx/edge-runtime ≥ 0.2.2 — earlier versions accept it but silently ignore it. metadata is ignored on every version (KV has no per-key metadata); it remains on the type, deprecated, so code that sets it keeps compiling.

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;
  sizeBytes?: number;   // stored value size, from the API's size_bytes
  updatedAt?: Date;     // last write time, from the API's updated_at
  /** @deprecated Not populated by the API. Always undefined. */
  metadata?: unknown;
}
const { keys } = await env.MY_KV.list({ prefix: "user/" });
// [{ name: "user/123", sizeBytes: 21, updatedAt: 2026-06-18T14:48:17.475Z }, …]
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. sizeBytes and updatedAt are populated from 0.2.2; on 0.2.1 entries carry only name.
KvKeyInfo.metadata is never populated — KV has no per-key metadata. It remains on the type, deprecated, so code that reads it keeps compiling.
  • Overview — the KV Runtime API surface at a glance
  • Quick Start — declare the binding and type it
  • REST API — the same operations over HTTP