The edge as a control plane: how Kinsta reworked its caching layer

Kinsta’s hosting stack is built on Google Cloud’s Premium Tier Network and C2 machines, but the company’s edge strategy is where it has made the biggest recent gains. By leaning more heavily on Cloudflare Workers and Workers KV, Kinsta improved its cache hit rate by 56.3% between October 2022 and March 2023, while simultaneously reducing the operational burden on its backend teams.

Before this change, rolling out a new feature meant deploying to hundreds of thousands of containers. Now, much of that logic lives in Workers, which can be updated across the edge with a few commands. This shift also made the cache far more responsive to client-side configuration changes, eliminating a whole class of stale-content problems.

A dynamic request router

Kinsta’s edge architecture treats every hosted domain as a key in Workers KV. The value for each domain holds the origin’s IP and port, a unique random ID, and any customer-enabled optimization options such as Polish, Image Resizing, or Auto Minify. Workers reads this data on every request to decide where the request should go and how it should be handled.

Routing to custom IPs and ports is done with resolveOverride, a Cloudflare-specific property of the Request object. This approach gives Kinsta full programmatic control over backend selection without touching DNS or load balancer configuration.

Why cache keys had to change

Workers KV’s one-minute cache propagation created an edge case. If a customer enabled Polish and a request arrived before the KV change had fully propagated, Kinsta would cache a non-optimized version of the asset. The customer then had to clear their cache manually — a frustrating loop that wasted API operations and GCP bandwidth on constant purges.

The solution was to make the cache key a function of the KV data itself. Instead of relying solely on the request URL, Kinsta appends the domain’s ID and any feature flags that could affect the asset (like Polish) to the cache key. The simplest implementation is to append a query parameter to the key:

When the cache differentiates by these additional parameters, the stale version becomes irrelevant. As soon as the KV update propagates, the cache key changes, and the next request naturally fetches and caches a fresh asset. Building this requires checking the URL for existing query parameters to pick the right connector (? or &) and ensuring the appended value is unique enough to prevent collisions.

Microcaching KV lookups

The customization of cache keys opened another optimization path: caching the Workers KV reads themselves with the Cache API. With billions of KV read operations per day, even small reductions matter. By storing KV responses in the cache, Kinsta cut down on repeated GET requests and shaved latency off each visitor request.

Long caching of KV data wasn’t an option, though. Customers constantly toggle features, exclude pages from caching, or change optimization settings and expect those changes to go live immediately. Kinsta instead adopted microcaching — holding KV data for under a minute of TTL.

In production, Kinsta set the cache TTL for KV data to 30 seconds. That single decision reduced KV read operations by roughly 80%.

const handleKVCache = async (event, myCustomDomain) => {
  // Try to get KV from cache first
  const cache = caches.default;
  let site_data = await cache.match( `https://${myCustomDomain}/some-string-ID-kv-data/` );

  // Valid KV cache match
  if (site_data && site_data.status === 200) {
    // ... modify your cached data if necessary, then return it
    return site_data;
  }

  // Invalid cache (expired, miss, etc), get data from KV namespace
  site_data = await KV_NAMESPACE.get(myCustomDomain.toLowerCase());
  
  // Cache valid KV responses with Cache API
  if (site_data) {
    let kvResponse = new Response(JSON.stringify(site_data), {status: 200});
    kvResponse.headers.set("Cache-Control", "public, s-maxage=30");
    event.waitUntil(cache.put(`https://${myCustomDomain}/some-string-ID-kv-data/`, kvResponse));
  }
  
  return site_data;
};

The result is a caching layer that adapts nearly instantly to customer changes, while offloading the coordination burden from Kinsta’s backend infrastructure. For teams running similar architectures, the three key takeaways are: use edge storage for routing logic, fold that logic into the cache key, and apply a short TTL to the storage lookups themselves.