loke.dev
Header image for The Day the Shared CDN Died: How Partitioned Caching Changed Web Performance Forever

The Day the Shared CDN Died: How Partitioned Caching Changed Web Performance Forever

Your favorite public CDN is no longer a performance shortcut—here is how the privacy-first web quietly killed the cross-site cache.

· 4 min read

Remember when we used to tell everyone to use Google Fonts or jQuery from a public CDN because "it's probably already in the user's cache"?

It was the ultimate free lunch of the 2010s. The logic was foolproof: if millions of sites use the same version of jQuery hosted on ajax.googleapis.com, the odds of a user arriving at *your* site with that file already tucked away in their browser cache were incredibly high. Zero-millisecond load times! It was the closest thing to magic we had in web performance.

Then, privacy happened. And just like that, the "Shared CDN" dream died a quiet, unceremonious death.

The Privacy Leak You Didn't Know You Had

To understand why the shared cache died, you have to understand how it was being abused.

In the old days, the browser's cache was a giant bucket keyed solely by the URL of the resource. If https://cdn.example.com/library.js was in the bucket, any site could ask for it and get it.

This created a massive privacy loophole called "Cache Probing." An attacker could try to load a specific resource in the background and measure how long it took.
- Fast load? You’ve visited a site that uses that resource.
- Slow load? You haven’t.

If a specific bank used a unique CSS file, a malicious site could "probe" your cache to see if you were a customer of that bank. It was a fingerprinting goldmine.

Enter: Partitioned Caching (The "Double Key")

To fix this, browser engines (starting with Safari/WebKit, then Firefox, and finally Chrome in late 2020) implemented Cache Partitioning.

Now, the cache key isn't just the URL. It’s a combination of the Top-Level Site and the Resource URL.

The Old Cache Key

Key = "https://cdnjs.com/ajax/libs/jquery/3.6.0/jquery.min.js"

The New Partitioned Key

Key = ("https://your-blog.com", "https://cdnjs.com/ajax/libs/jquery/3.6.0/jquery.min.js")

If the user goes to https://another-site.com, the browser looks for:

Key = ("https://another-site.com", "https://cdnjs.com/ajax/libs/jquery/3.6.0/jquery.min.js")

Even though the library URL is identical, the keys don't match. The browser treats them as two completely different files. The cross-site cache hit rate dropped to exactly zero.

Why This Actually Kind of Sucks (and Why It's Okay)

The performance benefit of using a public CDN for common libraries is gone. In fact, using a third-party CDN might now be *slower* than hosting the file yourself.

When you use a third-party domain, the browser has to perform:
1. DNS Lookup
2. TCP Handshake
3. TLS Negotiation

If you host the file on your own domain, you've already done that work to load the initial HTML.

Let's look at the "Before" (The Shared CDN approach)

<!-- This used to be a performance win. Now it's just an extra DNS lookup. -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.0/dist/vue.global.js"></script>

Let's look at the "After" (The Self-Hosted approach)

<!-- Fast, secure, and no extra connection overhead -->
<script src="/js/vendor/vue.3.2.0.js"></script>

How to Win in the Partitioned Era

If you're still relying on external CDNs for "cache hits," it’s time to pivot. Here is the modern playbook for web performance.

1. Self-Host Everything

Stop hotlinking. Download those libraries and serve them from your own infrastructure. If you’re using a build tool like Vite or Webpack, this happens automatically when you npm install.

// vite.config.js - Keeping things local and bundled
import { defineConfig } from 'vite';

export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['vue', 'axios'], // Bundle your heavy hitters locally
        },
      },
    },
  },
});

2. Use a "First-Party" CDN

If you want the benefits of a global edge network, use a CDN that masks as your own domain (like Cloudflare, Akamai, or Fastly). This keeps the connection "warm" and avoids the partitioned cache penalty because the resource shares your top-level domain.

3. Embrace HTTP/2 and HTTP/3

Since you're now hosting files yourself, you need to make sure you're not bottlenecked by old protocols. HTTP/2 allows you to stream multiple files over a single connection, making "unbundled" local files significantly faster than they used to be.

Check your headers to ensure you're actually using these:

# A quick way to check your protocol in the terminal
curl -I --http2 https://your-awesome-site.com

The "Preconnect" Band-Aid

If you *absolutely must* use a third-party CDN (maybe for a heavy video player or a map API), use a preconnect hint to get the connection handshake out of the way early.

<link rel="preconnect" href="https://maps.googleapis.com">
<link rel="dns-prefetch" href="https://maps.googleapis.com">

It won't fix the cache partitioning, but it will shave 200-500ms off the initial connection time.

Final Thoughts: The Death of the Shortcut

The "Shared CDN" was a clever hack that prioritized performance over privacy. But the web has shifted. Privacy isn't just a feature anymore; it's the default architecture.

The death of the shared cache means we have to be more intentional. We can't rely on the "work of others" to make our sites fast. We have to own our dependencies, optimize our own delivery pipelines, and realize that in 2024, the fastest code is the code you host yourself.

The free lunch is over, but honestly? The web is a much safer place because of it. Keep your scripts close, and your cache keys closer.