2026-01-20·Chiheb Nabil

Why Your Cloudflare Workers KV Bill Just Spiked (And How to Prevent It)

KV writes cost $5 per million — 16x more than reads. Learn why apps using KV as a general-purpose cache hit surprise bills, and how to monitor KV costs in real time.

cloudflarekvpricingcost-optimizationworkers

You checked your Cloudflare bill this morning and did a double-take. Your Workers project — a simple API with some caching — just cost $80 more than expected. The culprit? KV writes.

This happens more often than Cloudflare's docs suggest. Here's why KV bills spike, and how to catch it before it hurts.

The KV Pricing Trap

Cloudflare KV pricing looks harmless at first glance:

Operation Cost
KV Read $0.50 per million
KV Write $5.00 per million
KV Delete $5.00 per million
KV List $5.00 per million

Writes are 16x more expensive than reads. This asymmetry catches developers off guard because:

  1. Local development hides the costwrangler doesn't show write costs during testing
  2. Cache invalidation patterns generate writes — every time you "refresh" cache, that's a write
  3. High-frequency updates — session data, rate limiting counters, or analytics incrementing on every request

A Worker handling 100K requests/day with just one KV write per request costs $15/month in writes alone. Two writes per request? $30. Ten? $150.

Common KV Cost Traps

1. Using KV as a Session Store

Storing user sessions in KV seems natural, but session writes on every request add up fast:

// Expensive: writes on every request
export default {
  async fetch(request, env) {
    const sessionId = getSessionId(request);
    
    // This is a WRITE — $5 per million
    await env.SESSIONS.put(sessionId, JSON.stringify({
      lastSeen: Date.now(),
      requestCount: (await env.SESSIONS.get(sessionId))?.requestCount + 1 || 1
    }));
    
    return new Response("OK");
  }
};

Better approach: Use Durable Objects for mutable state, or Cache API for ephemeral session data.

2. Cache-Aside with Aggressive Invalidation

// Every cache miss + refresh = 1 read + 1 write
async function getDataWithCache(env, key) {
  let data = await env.CACHE.get(key);
  
  if (!data || isStale(data)) {
    data = await fetchFromOrigin(key);
    await env.CACHE.put(key, data); // $5 per million writes
  }
  
  return data;
}

If your cache hit ratio is 50%, you're doing one write per two requests. At 1M requests/day, that's $75/month in writes.

3. Rate Limiting Counters

// Incrementing a counter on every request
await env.RATE_LIMITS.put(
  `ratelimit:${ip}`, 
  JSON.stringify({ count: current + 1, window: Date.now() })
);

One write per request = $150/month at 1M requests/day.

Why You Don't See It Coming

Cloudflare's cost metrics have a 15-minute delay. By the time you see the spike in the dashboard, you've already paid for it. There's no real-time cost alerting built into the platform.

This is especially dangerous because:

  • Traffic spikes (viral post, DDoS, bot traffic) generate sudden write bursts
  • Code changes that accidentally increase write frequency go unnoticed
  • Retry storms from failed Workers can generate millions of writes in minutes

Monitoring KV Costs in Real Time

Since Cloudflare doesn't provide real-time cost alerts, you need to track it yourself. Here's a pattern using Tail Workers:

// tail-worker.js — track KV operations per request
export default {
  async tail(events, env, ctx) {
    for (const event of events) {
      // Count KV subrequests
      const kvWrites = event.subrequests?.filter(
        r => r.url?.includes('kv') && r.method === 'PUT'
      ).length || 0;
      
      if (kvWrites > 0) {
        // Send to your monitoring system
        await fetch('https://api.flarelog.dev/ingest', {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${env.FLARELOG_API_KEY}` },
          body: JSON.stringify({
            level: 'INFO',
            message: `KV write detected`,
            metadata: {
              kvWrites,
              estimatedCost: kvWrites * 0.000005, // $5 per million = $0.000005 per write
              worker: event.scriptName,
              colo: event.eventTimestamp
            }
          })
        });
      }
    }
  }
};

With this setup, you can:

  • Alert when KV writes exceed a threshold (e.g., >1000 writes/minute)
  • Track cost per request and identify expensive endpoints
  • Detect anomalies like sudden write spikes from traffic bursts

Better Alternatives for High-Write Workloads

If KV writes are eating your budget, consider these alternatives:

Use Case Better Alternative Why
Session data Durable Objects Mutable state without write costs
Ephemeral cache Cache API Free, in-memory, per-request
Rate limiting Durable Objects Atomic increments, no per-write cost
Analytics counters Durable Objects Batch updates, reduce write frequency
Config/data that rarely changes KV This is what KV is actually for

The 15-Minute Blind Spot

The real danger isn't just the cost — it's the delay in discovering it. A runaway Worker or traffic spike can generate thousands of dollars in KV writes before Cloudflare's dashboard updates.

This is where real-time monitoring becomes essential. With Tail Workers capturing subrequest data immediately, you can:

  1. Set cost thresholds and get alerted before the bill grows
  2. Identify the exact Worker and endpoint causing writes
  3. Correlate write spikes with traffic patterns or code deployments

Summary

KV is powerful for read-heavy, rarely-changing data. But using it as a general-purpose store or cache with frequent writes leads to surprise bills.

Key takeaways:

  • Writes cost 16x more than reads — design for read-heavy patterns
  • Cache API and Durable Objects are better for high-write use cases
  • Cloudflare's 15-minute cost delay means you find out too late
  • Real-time monitoring via Tail Workers catches spikes as they happen

Monitor your KV costs before they monitor your bank account.


Written by Chiheb Nabil, founder of FlareLog. Building observability tools for developers shipping on Cloudflare Workers.

Never miss an invisible crash again

FlareLog catches the errors Cloudflare can't log. Set up the Tail Worker in 5 minutes and see every crash, timeout, and cost spike in real time.

Start logging free →