Cloudflare CDN Hands-On: Cache Rules, Instant Purge, and URL Rewrites for Faster Web Apps

Cloudflare CDN Hands-On: Cache Rules, Instant Purge, and URL Rewrites for Faster Web Apps

Cloudflare can make a “normal” web app feel snappy by caching the right things at the edge (assets, images, sometimes even HTML) while keeping truly dynamic routes uncached. The trick is being intentional: pick what to cache, how long, and how to invalidate it safely.

In this hands-on guide, you’ll set up a practical caching strategy using Cache Rules, automate cache invalidation with the Purge Cache API, and clean up legacy URLs using URL Rewrite (Transform Rules). All examples are designed for junior/mid devs working on typical web apps (React/Next.js, Laravel, Django, etc.).

What we’ll build

  • Cache static assets aggressively (immutable files like /assets/app.9c1f2.js)
  • Cache images and fonts for a long time
  • Bypass cache for sensitive/dynamic routes (/api, /admin, authenticated pages)
  • Optionally cache HTML for marketing pages with a short TTL
  • Purge by URL from a deploy script when content changes
  • Rewrite old URLs to new paths without changing what users see

Step 0: Prerequisites (quick checklist)

  • Your DNS record is proxied through Cloudflare (orange cloud). Cache Rules require proxied traffic. :contentReference[oaicite:0]{index=0}
  • You can access the Cloudflare dashboard for your zone.
  • You have (or can create) an API token with permissions like Zone.Cache Purge (for purging) and rule-edit permissions if you automate rules.

Step 1: Add Cache Rules (the practical “safe defaults”)

Cache Rules are Cloudflare’s modern way to control caching behavior per-request (think “if request matches X, apply caching settings Y”). :contentReference[oaicite:1]{index=1}

Below are three rules that work well for most web apps. Create them in the dashboard (Cache Rules page) or via API. :contentReference[oaicite:2]{index=2}

Rule A: Cache static assets for a long time

Goal: cache fingerprinted files (hash in filename) very aggressively. These rarely change; when they do, the filename changes too.

  • Match: URI Path starts with /assets/ OR ends with .css, .js, .map
  • Action: Cache Everything
  • Edge TTL: e.g. 30 days (or longer)

Why it’s safe: if your build outputs hashed filenames (recommended), users won’t see stale assets because new deployments produce new URLs.

Rule B: Cache images & fonts long-term

  • Match: file extensions like .png, .jpg, .webp, .svg, .woff2
  • Action: Cache Everything
  • Edge TTL: e.g. 30 days

If you’re serving user-uploaded images that can be replaced at the same URL, keep the TTL shorter (or plan to purge those URLs after updates).

Rule C: Bypass cache for sensitive/dynamic routes

Goal: never cache endpoints that are user-specific or frequently changing.

  • Match: URI Path starts with /api/, /admin/, /login, /account
  • Action: Bypass cache

This is the “oops-prevention” rule. Cloudflare explicitly supports bypassing cache per rule. :contentReference[oaicite:3]{index=3}

Optional Rule D: Cache marketing HTML briefly

If you have mostly-static pages like /, /pricing, /docs, you can cache the HTML at the edge for a short time (like 5–10 minutes) to reduce origin load.

  • Match: exact paths /, /pricing, /about
  • Action: Cache Everything
  • Edge TTL: 5 minutes

Don’t do this for authenticated pages or anything personalized. If your HTML varies by cookie/header, you’ll need a more advanced approach (or keep HTML uncached).

Step 2: Automate rule creation with the Cloudflare API (optional, but useful)

If you want to version-control your caching logic, Cloudflare documents creating Cache Rules via API by updating a zone ruleset. :contentReference[oaicite:4]{index=4}

Example curl pattern (you’ll need your ZONE_ID and RULESET_ID):

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/$RULESET_ID" \ --request PUT \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --header "Content-Type: application/json" \ --data '{ "rules": [ { "enabled": true, "description": "Cache static assets", "action": "set_cache_settings", "expression": "(http.request.uri.path starts_with \"/assets/\") or (http.request.uri.path matches \"\\\\.(css|js|map)$\")", "action_parameters": { "cache": true, "edge_ttl": { "mode": "override_origin", "default": 2592000 } } }, { "enabled": true, "description": "Bypass API", "action": "set_cache_settings", "expression": "(http.request.uri.path starts_with \"/api/\") or (http.request.uri.path starts_with \"/admin/\")", "action_parameters": { "cache": false } } ] }'

Important: Cloudflare’s example warns that some “set all rules” requests can overwrite existing rules if used directly, so treat API updates carefully (fetch current rules first, then merge). :contentReference[oaicite:5]{index=5}

Step 3: Purge cache safely (purge by URL, not “purge everything”)

Cloudflare recommends purging specific URLs so you invalidate only what changed. Their docs call single-file purge (purge by URL) the recommended method. :contentReference[oaicite:6]{index=6}

Here’s a working example to purge a list of URLs:

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ --request POST \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --header "Content-Type: application/json" \ --data '{ "files": [ "https://example.com/pricing", "https://example.com/assets/app.9c1f2.js", "https://example.com/images/hero.webp" ] }'

If you’re using custom cache keys that vary by headers (device type, country, language), Cloudflare notes you may need to include those headers in the purge request to target the correct variants. :contentReference[oaicite:7]{index=7}

A deploy-friendly Node.js purge script

This is handy when you deploy a marketing site, update docs, or regenerate an RSS feed and want changes visible immediately.

/** * purge-cloudflare.js * Usage: * CLOUDFLARE_API_TOKEN=... ZONE_ID=... node purge-cloudflare.js \ * https://example.com/pricing https://example.com/sitemap.xml */ const [,, ...urls] = process.argv; if (!process.env.CLOUDFLARE_API_TOKEN || !process.env.ZONE_ID) { console.error("Missing CLOUDFLARE_API_TOKEN or ZONE_ID env vars"); process.exit(1); } if (!urls.length) { console.error("Provide one or more URLs to purge"); process.exit(1); } async function main() { const res = await fetch(`https://api.cloudflare.com/client/v4/zones/${process.env.ZONE_ID}/purge_cache`, { method: "POST", headers: { "Authorization": `Bearer ${process.env.CLOUDFLARE_API_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ files: urls }), }); const data = await res.json(); if (!res.ok || data.success !== true) { console.error("Purge failed:", JSON.stringify(data, null, 2)); process.exit(1); } console.log("Purged:", urls.length, "URL(s)"); } main().catch((err) => { console.error(err); process.exit(1); });

Tip: keep a small list of “always purge on deploy” URLs (like /, /pricing, /sitemap.xml, /rss.xml) rather than purging your entire cache.

Step 4: Fix legacy URLs with URL Rewrite (Transform Rules)

When you move routes (e.g., /blog/... becomes /articles/...), you can either redirect users (URL changes in browser) or rewrite internally (serve new content while keeping the old URL visible). Cloudflare’s URL Rewrite Rules do the latter. :contentReference[oaicite:8]{index=8}

Two practical uses:

  • Keep old links working without changing bookmarks
  • Normalize messy URLs (encoded slashes, legacy patterns)

Example rewrite concept:

  • If request path starts with /blog/
  • Rewrite to /marketing/ (or whatever your new section is)

Cloudflare’s examples gallery includes patterns like rewriting everything under /blog/<PATH> to /marketing/<PATH>. :contentReference[oaicite:9]{index=9}

Gotcha: URL Rewrite rules can rewrite path/query, but community guidance notes you can’t rewrite the hostname with Transform Rules; for host/origin changes you’d use other features (like Origin Rules). :contentReference[oaicite:10]{index=10}

Debugging checklist: “Why isn’t it caching?”

  • Rule order matters: ensure your bypass rules for /api don’t accidentally match broad paths you wanted cached.
  • Check headers: Cloudflare adds cache-related headers (like CF-Cache-Status) that help you see HIT/MISS at a glance.
  • Don’t cache personalized HTML: if you see “wrong user data” even once, stop caching that route and revisit your strategy.
  • Purge the exact URL: if your site uses both http and https or multiple hostnames, purge the one Cloudflare cached.

A simple, safe Cloudflare caching strategy (recap)

  • Cache immutable assets long (best ROI, lowest risk)
  • Cache media long (or purge on updates)
  • Bypass /api, /admin, auth, and user-specific pages
  • Optionally cache HTML briefly for public marketing pages
  • Purge by URL as part of deploy/content updates
  • Rewrite legacy paths to keep old links alive without messy app-side routing hacks

If you apply just Rules A–C and add a small purge script, you’ll usually see faster repeat loads, reduced origin load, and fewer “why is it stale?” surprises—without turning your CDN into a debugging nightmare.

::contentReference[oaicite:11]{index=11}


Leave a Reply

Your email address will not be published. Required fields are marked *