KV Binding

Key-value storage for small data with low latency. Ideal for caching, sessions, feature flags, and configuration.

KV stores values as JSON natively — you can put strings, numbers, booleans, objects, and arrays directly without manual serialization.

Setup

Go to KV in the sidebar and click New KV Namespace.

Enter a name (e.g., my-cache).

Then go to your worker's Environment, click Add Binding → select KV.

Set binding name (e.g., KV) and select your namespace.

Usage

export default {
  async fetch(request, env) {
    // Read a value
    const user = await env.KV.get('user:123');

    if (!user) {
      return new Response('Not found', { status: 404 });
    }

    return Response.json(user);
  }
};

Operations

get(key)

Read a value by key. Returns null if the key doesn’t exist or has expired.

// Returns the parsed value directly
const user = await env.KV.get('user:123');
// user is { name: 'John', role: 'admin' } — already an object

if (user === null) {
  console.log('Key not found');
}

TypeScript: Use the generic type parameter for type inference:

interface User {
  name: string;
  role: 'admin' | 'user';
}

const user = await env.KV.get<User>('user:123');
// user is User | null

put(key, value, options?)

Store a JSON-serializable value. Optionally set an expiration time.

// Store an object
await env.KV.put('user:123', { name: 'John', role: 'admin' });

// Store a string
await env.KV.put('greeting', 'Hello, World!');

// Store a number
await env.KV.put('counter', 42);

// With expiration (TTL in seconds)
await env.KV.put('session:abc', { userId: 123 }, { expiresIn: 3600 }); // Expires in 1 hour
OptionTypeDescription
expiresInnumberTime-to-live in seconds. Key will be automatically deleted after this time.

Note: Updating a key without expiresIn removes any existing expiration.

delete(key)

Delete a key.

await env.KV.delete('session:expired');

list(options?)

List all keys in the namespace. Returns an array of key names.

// List all keys
const keys = await env.KV.list();

// With prefix filter
const userKeys = await env.KV.list({ prefix: 'user:' });

// With limit
const firstTen = await env.KV.list({ limit: 10 });
OptionTypeDescription
prefixstringOnly return keys starting with this prefix.
limitnumberMaximum number of keys to return (default: 1000).

Use Cases

Session storage with expiration

export default {
  async fetch(request, env) {
    const sessionId = request.headers.get('Cookie')?.match(/session=(w+)/)?.[1];

    if (!sessionId) {
      return new Response('Unauthorized', { status: 401 });
    }

    const session = await env.KV.get(`session:${sessionId}`);

    if (!session) {
      return new Response('Session expired', { status: 401 });
    }

    // Refresh session TTL on activity
    await env.KV.put(`session:${sessionId}`, session, { expiresIn: 1800 });

    return new Response('OK');
  }
};

Feature flags

const flags = await env.KV.get('feature-flags') || {};

if (flags.newCheckout) {
  // Show new checkout flow
}

Rate limiting with auto-expiration

const ip = request.headers.get('CF-Connecting-IP');
const key = `ratelimit:${ip}`;
const count = (await env.KV.get(key)) || 0;

if (count > 100) {
  return new Response('Too many requests', { status: 429 });
}

// Auto-reset after 1 minute
await env.KV.put(key, count + 1, { expiresIn: 60 });

List and cleanup

// Find all sessions
const sessions = await env.KV.list({ prefix: 'session:' });

for (const key of sessions) {
  const data = await env.KV.get(key);

  if (shouldCleanup(data)) {
    await env.KV.delete(key);
  }
}

Limits

LimitValue
Key size512 bytes
Value size100 KB
Keys per namespaceUnlimited

Supported Value Types

KV stores JSON-serializable values. The following types are supported:

TypeExample
string'hello'
number42, 3.14
booleantrue, false
nullnull
array[1, 2, 3]
object{ name: 'John', age: 30 }

Note: Binary data (Uint8Array, ArrayBuffer) is not supported. Use the Storage binding for binary data.


KV vs Storage

FeatureKVStorage
Data modelJSON valuesFiles/blobs
LatencyLow (~ms)Medium (~100ms)
Max value100 KBUnlimited
ExpirationBuilt-in TTLManual
BinaryNoYes
Use caseCache, sessions, configFiles, uploads, backups

Use KV for small, frequently accessed JSON data with optional expiration. Use Storage for larger files or binary data.