Skip to content
Development
Skill

/cloudflare-kv

Cloudflare Workers KV global key-value storage. Use for namespaces, caching, TTL, or encountering KV_ERROR, 429 rate limits, consistency issues.

From plugin
secondsky-claude-skills
219183 skills42 agents62 commands2 MCP
Install
$ npx -y skills add secondsky/claude-skills --skill cloudflare-kv --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/cloudflare-kv

Context preview

The summary Claude sees to decide when to auto-load this skill.

Cloudflare Workers KV global key-value storage. Use for namespaces, caching, TTL, or encountering KV_ERROR, 429 rate limits, consistency issues.

SKILL.md

cloudflare-kv.SKILL.md
name: cloudflare-kv
description: "Cloudflare Workers KV global key-value storage. Use for namespaces, caching, TTL, or encountering KV_ERROR, 429 rate limits, consistency issues."
license: MIT
metadata:
  version: "3.0.0"
  last_verified: "2025-12-27"
  production_tested: true
  token_savings: "~60%"
  errors_prevented: 5
  templates_included: 5
  references_included: 7
  keywords:
    - kv storage
    - cloudflare kv
    - workers kv
    - kv namespace
    - kv bindings
    - kv cache
    - kv ttl
    - kv metadata
    - kv list
    - kv pagination
    - cache optimization
    - edge caching
    - KV_ERROR
    - 429 too many requests
    - kv rate limit
    - eventually consistent
    - wrangler kv
    - kv operations
    - key value storage

Cloudflare Workers KV

**Status**: Production Ready ✅ | **Last Verified**: 2025-12-27

---

What Is Workers KV?

Global key-value storage on Cloudflare edge:

  • Eventually consistent
  • Low latency worldwide
  • 1GB+ values supported
  • TTL expiration
  • Metadata support

---

Quick Start (5 Minutes)

1. Create KV Namespace

bunx wrangler kv namespace create MY_NAMESPACE
bunx wrangler kv namespace create MY_NAMESPACE --preview

2. Configure Binding

{
  "name": "my-worker",
  "main": "src/index.ts",
  "compatibility_date": "2025-10-11",
  "kv_namespaces": [
    {
      "binding": "MY_NAMESPACE",
      "id": "<PRODUCTION_ID>",
      "preview_id": "<PREVIEW_ID>"
    }
  ]
}

3. Basic Operations

export default {
  async fetch(request, env, ctx) {
    // Write
    await env.MY_NAMESPACE.put('key', 'value');

    // Read
    const value = await env.MY_NAMESPACE.get('key');

    // Delete
    await env.MY_NAMESPACE.delete('key');

    return new Response(value);
  }
};

**Load `references/setup-guide.md` for complete setup.**

---

KV API Methods

put() - Write

// Basic
await env.MY_NAMESPACE.put('key', 'value');

// With TTL (1 hour)
await env.MY_NAMESPACE.put('key', 'value', {
  expirationTtl: 3600
});

// With expiration timestamp
await env.MY_NAMESPACE.put('key', 'value', {
  expiration: Math.floor(Date.now() / 1000) + 3600
});

// With metadata
await env.MY_NAMESPACE.put('key', 'value', {
  metadata: { role: 'admin', created: Date.now() }
});

get() - Read

// Simple get
const value = await env.MY_NAMESPACE.get('key');

// With type
const text = await env.MY_NAMESPACE.get('key', 'text');
const json = await env.MY_NAMESPACE.get('key', 'json');
const buffer = await env.MY_NAMESPACE.get('key', 'arrayBuffer');
const stream = await env.MY_NAMESPACE.get('key', 'stream');

// With metadata
const { value, metadata } = await env.MY_NAMESPACE.getWithMetadata('key');

delete() - Remove

await env.MY_NAMESPACE.delete('key');

list() - List Keys

// Basic list
const { keys } = await env.MY_NAMESPACE.list();

// With prefix
const { keys } = await env.MY_NAMESPACE.list({
  prefix: 'user:',
  limit: 100
});

// Pagination
const { keys, cursor } = await env.MY_NAMESPACE.list({
  cursor: previousCursor
});

---

Critical Rules

Always Do ✅

1. **Use TTL** for temporary data 2. **Handle null** (key might not exist) 3. **Use metadata** for small data 4. **Paginate lists** (max 1000 keys) 5. **Use prefixes** for organization 6. **Cache in Worker** (avoid multiple KV calls) 7. **Use waitUntil()** for async writes 8. **Handle eventual consistency** 9. **Monitor rate limits** 10. **Use JSON.stringify** for objects

Never Do ❌

1. **Never assume instant** consistency 2. **Never exceed 25MB** per value 3. **Never list all keys** without pagination 4. **Never skip error handling** 5. **Never use for real-time** data 6. **Never exceed rate limits** (1000 writes/second) 7. **Never store secrets** unencrypted 8. **Never use as database** (no transactions) 9. **Never ignore metadata limits** (1024 bytes) 10. **Never skip TTL** for temporary data

---

Common Use Cases

Use Case 1: API Response Caching

const cacheKey = `api:${url}`;
let cached = await env.MY_NAMESPACE.get(cacheKey, 'json');

if (!cached) {
  cached = await fetch(url).then(r => r.json());
  await env.MY_NAMESPACE.put(cacheKey, JSON.stringify(cached), {
    expirationTtl: 300  // 5 minutes
  });
}

return Response.json(cached);

Use Case 2: User Preferences

const userId = '123';
const preferences = {
  theme: 'dark',
  language: 'en'
};

await env.MY_NAMESPACE.put(
  `user:${userId}:preferences`,
  JSON.stringify(preferences),
  {
    metadata: { updated: Date.now() }
  }
);

Use Case 3: Rate Limiting

const key = `ratelimit:${ip}`;
const count = parseInt(await env.MY_NAMESPACE.get(key) || '0');

if (count >= 100) {
  return new Response('Rate limit exceeded', { status: 429 });
}

await env.MY_NAMESPACE.put(key, String(count + 1), {
  expirationTtl: 60  // 1 minute window
});

Use Case 4: List with Prefix

const { keys } = await env.MY_NAMESPACE.list({
  prefix: 'user:',
  limit: 100
});

const users = await Promise.all(
  keys.map(({ name }) => env.MY_NAMESPACE.get(name, 'json'))
);

Use Case 5: waitUntil() Pattern

export default {
  async fetch(request, env, ctx) {
    // Don't wait for KV write
    ctx.waitUntil(
      env.MY_NAMESPACE.put('analytics', JSON.stringify(data))
    );

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

---

Limits (Summary)

**Key Limits:**

  • Key size: 512 bytes max
  • Value size: 25 MB max
  • Metadata: 1024 bytes max

**Rate Limits:**

  • Writes: 1000/sec per key
  • List: 100/sec per namespace
  • Reads: Unlimited

**For detailed limits, pricing, and optimization strategies, load `references/limits-quotas.md`**

---

Eventual Consistency

KV is **eventually consistent**:

  • Writes propagate globally (~60 seconds)
  • Not suitable for real-time data
  • Use D1 for strong consistency

**Pattern:**

// Write
aw
Read more
Ships withsecondsky-claude-skills

145 production-ready skills for Claude Code CLI 🔌 Platform / Harness Support These plugins ship as Claude Code marketplace plugins (.claude-plugin/ manifests) and Codex CLI plugins (.codex-plugin/ manifests).

Get the whole plugin

Other skills on secondsky-claude-skills.