Skip to content
Outer
Esc
↑↓navigate↵open⌘Jpreview
On this page

KV guide

Sessions, counters and flags in KV with void/kv — works on Outer today.

Verdict: works. KV is a standard binding for small state — sessions, counters, rate flags. Anything relational belongs in D1.

1. Declare it

In void.config.ts, under cloudflare. Edits need bun run build — bindings are read from the built config:

cloudflare: {
  kv_namespaces: [{ binding: "KV", id: "sessions" }],
},

2. Use it

import { kv } from "void/kv";

await kv.put("user:123", { name: "Alice" }, { ttl: 3600 });
const user = await kv.get<User>("user:123"); // JSON-parsed; invalid JSON → raw string
await kv.delete("user:123");
await kv.list({ prefix: "user:", limit: 100, cursor });

// Typed map with an automatic prefix
const sessions = kv.map<Session>("sessions");

Reads reach the cell that owns the namespace, so they never return a stale value — but writes to one namespace run one at a time, so a write-hot value like a busy counter belongs in a Durable Object. Never store the only copy of anything you can’t rebuild, and never secrets (use secret storage instead).

3. Deploy

kv_namespaces is an accepted deploy key (crates/outer/src/deploy/pipeline.rs), so the namespace deploys on every account — plan gating for bindings arrives with billing. celld creates the namespace on first use; a typo opens a silent empty namespace, so double-check the id.

Sources

Was this page helpful?