opdeck / blog / dogfooding-at-scale-migrating-cdnjs-to-cloudflare-s-develope

How to Migrate cdnjs to Cloudflare’s Developer Platform Step by Step

July 31, 2026 / OpDeck Team
CDN MigrationCloudflareDogfoodingInfrastructureDeveloper Tools

What "Dogfooding" Really Means for Infrastructure at Scale

The term "dogfooding" — eating your own dog food — gets thrown around a lot in software circles. It usually means a team uses their own product internally before shipping it to customers. But there's a meaningful difference between a small internal tool running on your own platform and serving 9 billion HTTP requests per day on it.

That's the scale Cloudflare is operating at with cdnjs, one of the internet's most widely used open-source CDN libraries. Moving cdnjs entirely onto Cloudflare's Developer Platform isn't just a marketing story — it's a real-world stress test that forced engineering teams to raise limits on Cloudflare Workers and Workflows for everyone. When infrastructure decisions at this scale happen, the ripple effects matter for every developer building on the platform.

This article breaks down what that migration actually involves technically, what it means for developers using Cloudflare's tooling, and how you can apply the same architectural thinking to your own CDN or high-traffic web infrastructure.


Understanding the cdnjs Architecture Challenge

cdnjs is a free, community-maintained CDN that hosts JavaScript libraries, CSS frameworks, fonts, and other static assets. It's been around since 2011 and is used by millions of websites globally. At 9 billion requests per day, it's not a hobby project — it's critical internet infrastructure.

Before the migration, cdnjs relied on a more traditional CDN setup. The challenge with migrating something like this isn't just moving files. It's about maintaining:

  • Zero-downtime delivery — any interruption affects millions of sites simultaneously
  • Cache efficiency — static assets need extremely high cache hit rates to stay cost-effective
  • Origin resilience — the origin must handle cache misses without collapsing
  • Versioned asset immutability — library versions never change, so cache headers need to reflect that permanently

These constraints are actually well-suited to a Workers-based architecture, but they require careful design.


How Cloudflare Workers Handle High-Volume Static Asset Delivery

At the core of the migration is Cloudflare Workers, which lets you intercept and manipulate HTTP requests at the edge — inside Cloudflare's global network — without managing servers.

Here's a simplified example of how a Worker can handle CDN-style asset routing:

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    
    // Parse library name and version from path
    // e.g. /ajax/libs/jquery/3.7.1/jquery.min.js
    const pathParts = url.pathname.split('/');
    const libraryName = pathParts[3];
    const version = pathParts[4];
    const filename = pathParts.slice(5).join('/');

    // Construct cache key
    const cacheKey = new Request(
      `https://assets.example.com/${libraryName}/${version}/${filename}`,
      request
    );

    const cache = caches.default;
    let response = await cache.match(cacheKey);

    if (!response) {
      // Fetch from R2 or origin storage
      response = await env.ASSETS_BUCKET.get(
        `${libraryName}/${version}/${filename}`
      );

      if (!response) {
        return new Response('Not Found', { status: 404 });
      }

      // Versioned assets are immutable — cache forever
      response = new Response(response.body, {
        headers: {
          'Cache-Control': 'public, max-age=31536000, immutable',
          'Content-Type': getContentType(filename),
          'Access-Control-Allow-Origin': '*',
        },
      });

      // Store in edge cache
      await cache.put(cacheKey, response.clone());
    }

    return response;
  }
};

The key insight here is that versioned library files are immutable. jQuery 3.7.1 will never change. That means you can set max-age=31536000, immutable and trust that Cloudflare's edge cache will serve subsequent requests without ever touching your origin. Cache hit rates on well-configured CDN infrastructure like this routinely exceed 99%.


Cloudflare R2: The Storage Layer That Makes This Practical

One reason this migration is architecturally interesting is the use of Cloudflare R2 as the underlying storage layer. R2 is Cloudflare's S3-compatible object storage, but with one critical difference: zero egress fees.

For a CDN serving billions of requests, egress costs on traditional cloud storage (AWS S3, GCS) would be enormous. R2 eliminates that cost entirely, which is what makes it practical to use as the origin for a high-traffic CDN.

The integration between Workers and R2 is tight:

// Binding R2 bucket in wrangler.toml
[[r2_buckets]]
binding = "ASSETS_BUCKET"
bucket_name = "cdnjs-assets"

// Accessing in Worker
const object = await env.ASSETS_BUCKET.get(objectKey);
if (object === null) {
  return new Response('Object Not Found', { status: 404 });
}

return new Response(object.body, {
  headers: {
    'etag': object.httpEtag,
    'content-type': object.httpMetadata.contentType,
    'cache-control': 'public, max-age=31536000, immutable',
  },
});

This pattern — Worker at the edge, R2 as origin, edge cache in between — is a solid architecture for any static asset delivery system.


Cloudflare Workflows: Handling Background Processing at Scale

One of the less-discussed aspects of the cdnjs migration is the use of Cloudflare Workflows for background processing. cdnjs isn't just a static file server — it has an active pipeline that:

  • Accepts pull requests from the community to add or update libraries
  • Validates package metadata
  • Fetches and processes npm packages
  • Uploads processed files to storage
  • Updates metadata APIs

These are long-running, multi-step processes that don't fit neatly into a single Worker request (which has a maximum execution time). Workflows solve this by letting you define durable, multi-step processes that can pause, retry, and resume across Worker invocations.

import { WorkflowEntrypoint } from 'cloudflare:workers';

export class LibraryIngestionWorkflow extends WorkflowEntrypoint {
  async run(event, step) {
    const { library, version, npmPackage } = event.payload;

    // Step 1: Validate the package exists on npm
    const packageInfo = await step.do('validate-npm-package', async () => {
      const response = await fetch(
        `https://registry.npmjs.org/${npmPackage}/${version}`
      );
      if (!response.ok) throw new Error('Package not found on npm');
      return response.json();
    });

    // Step 2: Download and extract the package
    const files = await step.do('download-package', async () => {
      return await downloadAndExtractNpmTarball(packageInfo.dist.tarball);
    });

    // Step 3: Upload files to R2
    await step.do('upload-to-r2', async () => {
      for (const file of files) {
        await env.ASSETS_BUCKET.put(
          `${library}/${version}/${file.name}`,
          file.content,
          { httpMetadata: { contentType: file.mimeType } }
        );
      }
    });

    // Step 4: Update metadata
    await step.do('update-metadata', async () => {
      await updateLibraryMetadata(library, version, files);
    });
  }
}

The critical feature here is durability. If any step fails, the Workflow retries from that step — not from the beginning. For a process that involves downloading large npm tarballs and uploading hundreds of files, this resilience is essential.

Cloudflare noted that this migration pushed Workflows limits higher for all users. That's a direct benefit of dogfooding — when your own critical infrastructure hits a limit, you fix the limit.


What This Migration Means for Your Own CDN Setup

If you're running a CDN, a static asset pipeline, or any high-traffic file delivery system, the cdnjs migration offers several practical lessons.

1. Cache Headers Are Your Most Important Performance Tool

For immutable versioned assets, aggressive caching is the right call. But many developers are too conservative with cache headers out of fear of serving stale content. The solution is versioning in the URL — when the version is part of the path, you never need to invalidate the cache. You just deploy a new version at a new path.

You can verify your current cache configuration using the Cache Inspector tool, which analyzes HTTP cache headers and tells you exactly what's being cached, for how long, and whether your Cache-Control directives are configured correctly.

2. Separate Your Delivery Layer from Your Processing Layer

One of the cleanest architectural decisions in the cdnjs setup is the clear separation between:

  • Delivery (Workers + edge cache serving files to end users)
  • Processing (Workflows handling ingestion, validation, and storage)

These have completely different requirements. Delivery needs to be fast, stateless, and massively parallel. Processing needs to be reliable, durable, and fault-tolerant. Mixing them into a single system creates fragility.

3. Monitor Your DNS Configuration Carefully

At 9 billion requests per day, even a brief DNS misconfiguration can cause catastrophic outages. When you're running infrastructure at this scale — or even at much smaller scales — DNS health is non-negotiable.

The DNS Lookup tool lets you inspect DNS records across record types (A, AAAA, CNAME, MX, TXT, NS) and verify that your configuration is resolving correctly from multiple vantage points. For CDN infrastructure specifically, you'll want to verify that CNAME records are pointing to the right edge endpoints and that TTLs are set appropriately.

4. Verify SSL Certificate Configuration

A CDN serving assets for millions of websites needs bulletproof SSL. Certificate expiry, misconfigured SANs, or weak cipher suites can break asset loading across a huge number of dependent sites simultaneously.

Use the SSL Certificate Checker to audit your certificate configuration — it checks expiry dates, certificate chain validity, supported protocols, and cipher strength. For CDN infrastructure, you should be running this check regularly as part of your operational monitoring.


Detecting Whether a Site Uses Cloudflare (And Why It Matters)

One practical application of understanding the cdnjs architecture is knowing how to detect Cloudflare's presence in a CDN stack. If you're debugging asset delivery issues, understanding whether a request is being served through Cloudflare — and how — is essential diagnostic information.

Cloudflare adds specific response headers that identify its presence:

  • CF-Ray — a unique identifier for each request processed through Cloudflare
  • CF-Cache-Status — tells you whether the response was a HIT, MISS, EXPIRED, or BYPASS
  • Server: cloudflare — identifies the server software
curl -I https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js

# Look for:
# CF-Ray: 7a1b2c3d4e5f6789-LHR
# CF-Cache-Status: HIT
# Cache-Control: public, max-age=30672000
# Server: cloudflare

The CF-Cache-Status: HIT response is what you want to see for static assets. A MISS means the request went all the way to origin, which is expensive and slow.

You can also use the Cloudflare Detection tool to automatically check whether a given domain is proxied through Cloudflare and inspect the associated headers.


Performance Benchmarking Your CDN Assets

Once you have your CDN architecture in place, you need to actually measure its performance. Theoretical cache hit rates are one thing — real-world latency from different geographic regions is another.

A few things to measure:

Time to First Byte (TTFB) — for cached CDN assets, TTFB should be under 50ms from most locations. If you're seeing 200-500ms TTFB, your cache hit rate is likely low or your origin is slow.

Cache Hit Rate — monitor this in your CDN analytics. For versioned static assets, you should be targeting 99%+ cache hit rates after warmup.

Asset Load Time by Region — CDN performance varies significantly by geography. An asset that loads in 20ms in Europe might take 200ms in Southeast Asia if your CDN doesn't have good PoP coverage in that region.

The Website Performance Analyzer runs a Lighthouse-based audit that includes asset loading analysis and can help identify whether your CDN-delivered assets are contributing to performance bottlenecks on your pages.


Security Considerations for CDN Infrastructure

The cdnjs migration also surfaces important security considerations that are easy to overlook when you're focused on performance.

Subresource Integrity (SRI) — when you serve third-party scripts from a CDN, you should always include SRI hashes in your script tags:

<script 
  src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"
  integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ=="
  crossorigin="anonymous"
  referrerpolicy="no-referrer">
</script>

SRI ensures that even if the CDN is compromised, a modified script won't execute in your users' browsers.

Security Headers — any CDN or web infrastructure should be serving appropriate security headers. The Vulnerability Scanner checks for common security misconfigurations including missing security headers (Content-Security-Policy, X-Frame-Options, X-Content-Type-Options), XSS vulnerabilities, and other common issues.

CORS Configuration — CDN assets need permissive CORS headers (Access-Control-Allow-Origin: *) to be usable across different origins. But make sure you're not inadvertently applying that same permissive policy to API endpoints on the same domain.


The SEO Angle: CDN Performance and Search Rankings

There's a direct line between CDN performance and SEO outcomes. Google's Core Web Vitals — particularly Largest Contentful Paint (LCP) and First Input Delay (FID) — are heavily influenced by how quickly your assets load.

If your JavaScript and CSS files are being served from a slow or misconfigured CDN, it directly impacts your Core Web Vitals scores, which feed into search rankings. The SEO Audit tool analyzes your page's meta tags, content structure, and performance signals, giving you a clear picture of where CDN-related issues might be affecting your search visibility.


Conclusion

The cdnjs migration to Cloudflare's Developer Platform is a useful case study not because of the brand involved, but because of the engineering discipline it demonstrates. Serving 9 billion requests per day on Workers, R2, and Workflows — and being forced to raise platform limits in the process — is a genuine proof of concept for this architectural pattern.

The core lessons are practical and applicable at any scale: use immutable versioning to enable aggressive caching, separate delivery from processing, monitor DNS and SSL rigorously, and measure real-world performance rather than relying on theoretical guarantees.

Whether you're running a personal project CDN or building infrastructure that serves millions of users, the same principles apply.

Ready to audit your own infrastructure? OpDeck provides a full suite of tools — from DNS Lookup and SSL Certificate Checker to Cache Inspector and Website Performance Analyzer — that let you inspect, diagnose, and optimize your web infrastructure without installing anything. Head to opdeck.co and start with a free audit of your domain.