KV API Reference
Read Operations
// Single key (string)
const value = await env.MY_KV.get('user:123')
// JSON type (auto-parsed)
const config = await env.MY_KV.get<AppConfig>('config', 'json')
// ArrayBuffer for binary
const buffer = await env.MY_KV.get('image', 'arrayBuffer')
// Stream for large values
const stream = await env.MY_KV.get('large-file', 'stream')
// With cache TTL (min 60s)
const value = await env.MY_KV.get('key', { type: 'text', cacheTtl: 300 })
// Bulk get (max 100 keys, counts as 1 operation)
const keys = ['user:1', 'user:2', 'user:3', 'missing:key']
const results = await env.MY_KV.get(keys)
// Returns Map<string, string | null>
console.log(results.get('user:1')) // "John" (if exists)
console.log(results.get('missing:key')) // null
// Process results with null handling
for (const [key, value] of results) {
if (value !== null) {
// Handle found keys
console.log(`${key}: ${value}`)
}
}
// TypeScript with generics (type-safe JSON parsing)
interface UserProfile {
name: string
email: string
}
const profile = await env.USERS.get<UserProfile>('user:123', 'json')
// profile is typed as UserProfile | null
if (profile) {
console.log(profile.name) // Type-safe access
}
// Bulk get with type
const configs = await env.MY_KV.get<Config>(['config:app', 'config:feature'], 'json')
// Map<string, Config | null>
Write Operations
// Basic put
await env.MY_KV.put('key', 'value')
await env.MY_KV.put('config', JSON.stringify({ theme: 'dark' }))
// With expiration (UNIX timestamp)
await env.MY_KV.put('session', token, {
expiration: Math.floor(Date.now() / 1000) + 3600,
})
// With TTL (seconds from now, min 60)
await env.MY_KV.put('cache', data, { expirationTtl: 300 })
// With metadata (max 1024 bytes)
await env.MY_KV.put('user:profile', userData, {
metadata: { version: 2, lastUpdated: Date.now() },
})
// Combined
await env.MY_KV.put('temp', value, {
expirationTtl: 3600,
metadata: { temporary: true },
})
Get with Metadata
// Single key
const result = await env.MY_KV.getWithMetadata('user:profile')
// { value: string | null, metadata: any | null }
if (result.value && result.metadata) {
const { version, lastUpdated } = result.metadata
}
// Multiple keys (bulk)
const keys = ['key1', 'key2', 'key3']
const results = await env.MY_KV.getWithMetadata(keys)
// Returns Map<string, { value, metadata, cacheStatus? }>
for (const [key, result] of results) {
if (result.value) {
console.log(`${key}: ${result.value}`)
console.log(`Metadata: ${JSON.stringify(result.metadata)}`)
// cacheStatus field indicates cache hit/miss (when available)
}
}
// With type
const result = await env.MY_KV.getWithMetadata<UserData>('user:123', 'json')
// result: { value: UserData | null, metadata: any | null, cacheStatus?: string }
Delete Operations
await env.MY_KV.delete('key') // Always succeeds (even if key missing)
List Operations
// List all
const keys = await env.MY_KV.list()
// { keys: [...], list_complete: boolean, cursor?: string }
// With prefix
const userKeys = await env.MY_KV.list({ prefix: 'user:' })
// Pagination
let cursor: string | undefined
let allKeys = []
do {
const result = await env.MY_KV.list({ cursor, limit: 1000 })
allKeys.push(...result.keys)
cursor = result.cursor
} while (!result.list_complete)
Performance Considerations
Type Selection
| Type | Use Case | Performance |
|---|---|---|
stream |
Large values (>1MB) | Fastest - no buffering |
arrayBuffer |
Binary data | Fast - single allocation |
text |
String values | Medium |
json |
Objects (parse overhead) | Slowest - parsing cost |
Parallel Reads
// Efficient parallel reads with Promise.all()
const [user, settings, cache] = await Promise.all([
env.USERS.get('user:123', 'json'),
env.SETTINGS.get('config:app', 'json'),
env.CACHE.get('data:latest'),
])
Error Handling
- Missing keys: Return
null(not an error) - Rate limit (429): Retry with exponential backoff (see gotchas.md)
- Response too large (413): Values >25MB fail with 413 error
See gotchas.md for detailed error patterns and solutions.