Cache Configuration
By the end of this lesson you will understand every setting on the Cloudflare Caching → Configuration dashboard page, what each one does, the correct value for most sites, and the operational impact of each option.
Overview: The Configuration Dashboard
The Caching → Configuration page is Cloudflare's global cache control panel. Unlike Cache Rules (which target specific URL patterns), these settings apply zone-wide as defaults — they establish baseline behaviour for your entire domain before any per-URL rules run.
flowchart TD
REQ["Incoming Request"] --> CFG["Zone-Wide Cache Configuration\n(global defaults)"]
CFG --> RULES["Cache Rules\n(per-URL overrides)"]
RULES --> EDGE["Edge Cache\n(serve or miss)"]
style CFG fill:#f6821f,color:#fff,stroke:#e5711e
style RULES fill:#2563eb,color:#fff,stroke:#1e40af
style EDGE fill:#16a34a,color:#fff,stroke:#15803d
Think of it this way: Configuration sets the floor; Cache Rules punch holes in or raise the ceiling for specific paths.
Quick Reference
| Setting | Default | Free? | Impact |
|---|---|---|---|
| Caching Level | Standard | ✅ | Controls query-string caching |
| Browser Cache TTL | Respect Origin | ✅ | How long browsers cache files locally |
| Purge Cache | N/A (action) | ✅ | Immediately clears cached content from edge |
| Development Mode | Off | ✅ | Bypasses edge cache for 3 hours |
| Always Online™ | Off | ✅ | Serves stale pages when origin is down |
| Crawler Hints | Off | ✅ | Notifies crawlers of content changes |
| CSAM Scanning Tool | Off | ✅ | Scans cached images for illegal content |
| Query String Sort | Off | ❌ Enterprise | Normalises query string key order |
Caching Level
Caching Level controls how Cloudflare treats query strings (the ?key=value part of a URL) when deciding whether a cached version already exists.
The Three Levels
| Level | Behaviour | Example |
|---|---|---|
| No Query String | Only cache if URL has no query string | Caches /image.png; ignores /image.png?v=2 |
| Ignore Query String | Cache based on path only — ignore query strings entirely | /style.css?v=1 and /style.css?v=999 served from the same cache entry |
| Standard (default) | Cache using the full URL including query string | /page?lang=en and /page?lang=fr are separate cache entries |
Which Level Should You Use?
flowchart TD
Q1{"Do your query strings\nchange the content?"}
Q1 -->|"Yes (e.g., ?lang=en, ?id=42)"| STD["Use Standard\n(default — safe choice)"]
Q1 -->|"No (e.g., ?utm_campaign=email)"| Q2{"Do you want to cache\nbased on path only?"}
Q2 -->|"Yes — marketing/tracking params only"| IGN["Use Ignore Query String\n(highest cache efficiency)"]
Q2 -->|"Unsure"| STD
style STD fill:#16a34a,color:#fff,stroke:#15803d
style IGN fill:#2563eb,color:#fff,stroke:#1e40af
Standard is the right choice for most sites. It is safe: two different query strings always produce two separate cache entries, so you never risk serving the wrong content.
Ignore Query String is powerful for static asset paths where the query string is a cache-busting suffix or a marketing tag — not a content selector. For example:
style.css?v=20240301→ cache entry is just/style.csslogo.png?utm_source=twitter→ cache entry is just/logo.png
Never set Ignore Query String if your site uses query strings to serve different content to different users (e.g., /product?id=42 vs /product?id=99). Both would be served from the same cache entry — showing the wrong product to users.
No Query String is rarely the right choice. It means only the exact URL /file.ext (with no ?...) is ever cached. Any URL with a query string becomes DYNAMIC. Useful only for extremely strict caching of bare asset paths.
Configure via API
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/settings/cache_level" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"value": "ignore_query_string"}'
# Values: "aggressive" (Ignore) | "simplified" (No Query String) | "basic" (Standard)
Browser Cache TTL
Browser Cache TTL controls the max-age directive that Cloudflare sends to the visitor's browser. This instructs the browser how long to cache a file locally before re-requesting it from Cloudflare.
Behaviour Modes
| Setting | What Cloudflare Does |
|---|---|
| Respect Existing Headers (default) | Passes through the Cache-Control headers from your origin untouched |
| Set a specific TTL | Overrides the max-age value sent to browsers, regardless of what your origin says |
Available TTL Values
Values range from 30 minutes to 1 year:
30 min → 1 hr → 2 hr → 3 hr → 4 hr → 5 hr → 8 hr → 12 hr → 16 hr → 20 hr → 1 day → 2 day → 3 day → 4 day → 5 day → 6 day → 1 week → 2 week → 1 month → 1 year
When to Override Browser TTL
| Scenario | Recommended TTL | Reasoning |
|---|---|---|
| Static assets with hashed filenames | 1 year | Safe because hash changes when file updates |
| HTML pages | Respect headers or 1 hour | Content changes — short browser cache enables fast updates |
| API responses | Respect headers or no-store (via origin) | User-specific; should not linger in browser |
| Font files | 1 week to 1 month | Fonts rarely change |
| Images (non-versioned) | 1 day | Balance freshness and performance |
Browser TTL is not purgeable from the Cloudflare dashboard. Once a browser caches a file for (say) 7 days, you cannot force that specific user's browser to fetch a new version until the TTL expires. This is why short browser TTLs with frequent deploys should use cache-busting filenames (content-hashed assets) rather than relying on short TTLs alone.
Configure via API
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/settings/browser_cache_ttl" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"value": 86400}'
Purge Cache
Purge Cache is an action, not a persistent setting. It immediately invalidates content stored in Cloudflare's edge caches — forcing the next request for each purged URL to fetch a fresh copy from your origin.
Purge Methods
| Method | Scope | When to Use | How |
|---|---|---|---|
| Purge Everything | All cached content on your zone | Major redesign, framework update, emergency fix | Dashboard → Caching → Purge Cache → Purge Everything |
| Custom Purge (by URL) | One or more specific URLs | Updated an image, changed a CSS file | Dashboard → Caching → Purge Cache → Custom Purge |
| Purge by Tag | All URLs sharing a Cache-Tag header value | Purge a category of related content | API — Enterprise only |
| Purge by Prefix | All URLs matching a path prefix | Purge all content under /blog/ | API — Enterprise only |
| Purge by Hostname | All cached content for a specific hostname | Multi-hostname zone cleanup | API — Enterprise only |
Purge by URL via API
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"files": [
"https://example.com/assets/style.css",
"https://example.com/images/hero.jpg"
]
}'
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"purge_everything": true}'
Purge Propagation Time
Purge commands propagate globally across Cloudflare's 330+ PoPs within approximately 30 seconds. During that window, some PoPs may still serve the old cached version. This is generally acceptable — and can be mitigated for critical updates by using cache-busting filenames in your deploy pipeline rather than relying on purge timeliness.
"Purge Everything" clears your entire edge cache. Every object must be re-fetched from your origin on the next request — this can cause a spike in origin load lasting several minutes while the cache repopulates. Use targeted URL purges whenever possible, especially on high-traffic sites.
Automating Purge in CI/CD
#!/bin/bash
# Run this after deploying new static assets
ZONE_ID="your_zone_id"
CF_TOKEN="your_api_token"
# Purge specific updated files
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"files": [
"https://example.com/index.html",
"https://example.com/sitemap.xml"
]
}'
echo "Cache purge complete"
Development Mode
Development Mode temporarily bypasses Cloudflare's edge cache for 3 hours, forcing every request to go directly to your origin server. This lets you see changes in real-time without waiting for cached versions to expire.
How It Works
sequenceDiagram
participant U as Browser
participant CF as Cloudflare Edge
participant O as Origin
Note over CF: Development Mode OFF (normal)
U->>CF: GET /style.css
CF-->>U: 200 OK (cache HIT — fast)
Note over CF: Development Mode ON
U->>CF: GET /style.css
CF->>O: Forward request (bypass cache)
O-->>CF: 200 OK (fresh)
CF-->>U: 200 OK (always fresh)
| Aspect | Details |
|---|---|
| Duration | 3 hours from activation (then auto-disables) |
| Cache impact | Bypasses edge cache — does not purge it |
| Origin load | Significantly increased — all traffic hits your origin |
| After expiry | Cache is not cleared automatically — old cached content returns |
Development Mode bypasses the cache while active, but when it automatically expires after 3 hours, Cloudflare resumes serving whatever was previously cached. If you made changes you want visitors to see permanently, manually purge the cache before or after disabling Development Mode.
Configure via API
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/settings/development_mode" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"value": "on"}'
When to Use Development Mode
| Good Use | Poor Use |
|---|---|
| CSS/JS changes during active development | On a production site with high traffic |
| Quick debugging of a visual issue | As a substitute for a proper staging environment |
| Verifying a fix before purging | Long-running dev sessions (it auto-disables after 3 hrs) |
Always Online™
Always Online™ keeps a cached version of your website accessible to visitors even when your origin server is completely unreachable (crash, maintenance, network outage). It does this by serving fallback pages from the Internet Archive's Wayback Machine.
How It Works
flowchart LR
USER["Visitor"] --> CF["Cloudflare Edge"]
CF -->|"Origin reachable"| ORIGIN["Your Server\n(200 OK)"]
CF -->|"Origin unreachable\n(Always Online™ active)"| IA["Wayback Machine\n(Cached Snapshot)"]
IA -->|"Serve archived page"| CF
CF -->|"Degraded but available"| USER
style ORIGIN fill:#16a34a,color:#fff,stroke:#15803d
style IA fill:#f59e0b,color:#fff,stroke:#d97706
Important Limitations
| Aspect | Details |
|---|---|
| Source | Pages from the Internet Archive — may be days, weeks, or months old |
| Scope | HTML pages only — not API responses, authenticated sessions, or dynamic content |
| Dynamic features | Broken — forms, shopping carts, logins won't work on archived pages |
| Privacy | Enabling this feature shares your site's content with the Internet Archive |
| Activation | Only activates when Cloudflare cannot connect to your origin (521/522/523/524 errors) |
| Best for | Informational / content sites (blogs, docs, marketing sites) |
Always Online™ is not a replacement for a proper high-availability setup. For business-critical applications, use load balancing, standby servers, or a static fallback page served via Cloudflare Pages instead.
Crawler Hints
Crawler Hints is a protocol that allows Cloudflare to proactively notify search engines and web crawlers (Googlebot, Bingbot, etc.) when your site's content has changed — rather than waiting for the crawler to discover it on its own schedule.
How It Works
When you update content and purge Cloudflare's cache, Crawler Hints generates a change notification that crawlers subscribed to this protocol can act on immediately. The result:
| Without Crawler Hints | With Crawler Hints |
|---|---|
| Crawlers visit on their own schedule (hours or days later) | Crawlers notified of change within minutes |
| Outdated content may persist in search results longer | Search results updated faster after content changes |
| Crawlers may waste bandwidth rechecking unchanged pages | Crawlers focus effort on actually changed URLs |
Considerations
- Privacy: Cloudflare shares URL change signals with participating crawlers. Review the Supplemental Terms before enabling.
- SEO benefit: Useful for frequently updated sites (news, e-commerce, documentation) where fast indexing matters.
- Low risk: Does not affect caching behaviour — it is a notification-only system.
CSAM Scanning Tool
The CSAM (Child Sexual Abuse Material) Scanning Tool is a protective measure that scans hashes of your cached images against a database of known illegal content hashes. It does not scan for adult content generally — it specifically targets known illegal material.
How It Works
| Step | Action |
|---|---|
| 1 | Cloudflare computes a hash of each cached image on your zone |
| 2 | Hash is compared against known CSAM hash databases |
| 3 | On a match: the URL is immediately blocked (returns 451 Unavailable For Legal Reasons) |
| 4 | You receive an email alert with the file path so you can remove the original |
| 5 | Cloudflare reports the match to relevant authorities |
Who Should Enable This?
| Site Type | Recommendation |
|---|---|
| User-generated content platforms (forums, social, file hosts) | ✅ Strongly recommended |
| E-commerce with user-uploaded product images | ✅ Recommended |
| Static informational site (no user uploads) | Optional — low risk either way |
| News / editorial content (professional images only) | Optional |
This tool only scans content that is cached by Cloudflare. It does not scan files stored on your server that are not being served through Cloudflare. Ensure your origin-level safeguards are also in place.
Query String Sort (Enterprise)
Query String Sort normalises the order of query string parameters before generating a cache key. This means ?a=1&b=2 and ?b=2&a=1 are treated as the same URL and served from the same cache entry.
Why It Matters
Many frontend frameworks, analytics tools, and CDN integrations generate URLs with query parameters in unpredictable orders. Without Query String Sort, these generate separate cache entries for identical content:
/product?color=red&size=M → Cache entry A
/product?size=M&color=red → Cache entry B ← identical content, wasted cache slot
With Query String Sort: both are normalised to the same sorted key → one cache entry, higher HIT ratio.
| Feature | Free | Pro | Biz | Enterprise |
|---|---|---|---|---|
| Query String Sort | ❌ | ❌ | ❌ | ✅ |
For non-Enterprise plans, the closest equivalent is setting Caching Level → Ignore Query String for paths where the query string is irrelevant — though that is an all-or-nothing approach per Caching Level setting.
Putting It All Together
Here is the recommended configuration baseline for a typical web application:
| Setting | Recommended Value | Reason |
|---|---|---|
| Caching Level | Standard | Safe default; preserves query-string specificity |
| Browser Cache TTL | Respect Origin (or 1 day) | Let your origin control TTL; override only if origin doesn't set headers |
| Development Mode | Off | Enable only during active local debugging sessions |
| Always Online™ | On (for content sites) | Provides a basic safety net during origin outages |
| Crawler Hints | On | Improves search indexing speed with no downside |
| CSAM Scanning | On (if user uploads exist) | Protective measure with no performance impact |
Common Misconceptions
"Development Mode purges my cache when I enable it"
Reality: Development Mode bypasses the cache — it does not purge it. When Development Mode expires after 3 hours, Cloudflare goes back to serving whatever was in the cache before you enabled it. You must manually purge if you want visitors to see your changes after development.
"Browser Cache TTL and Edge Cache TTL are the same setting"
Reality: They control different caches entirely. Edge Cache TTL (set via Cache Rules) controls how long Cloudflare's servers hold the content. Browser Cache TTL (set here) controls how long the visitor's browser holds it locally. Content evicted from the edge cache can still be in the browser cache — and vice versa.
"Purge Everything is safe to run frequently"
Reality: Purge Everything clears 100% of your cached content. Every single subsequent request becomes a cache MISS and hits your origin. On high-traffic sites this can cause a severe origin traffic spike. Prefer targeted URL purges combined with cache-busting filenames in your deployment pipeline.
"Caching Level: Ignore Query String is always better for performance"
Reality: Ignore Query String is only safe when query strings truly don't affect content. If your application serves different pages at /news?page=2 vs /news?page=3, Ignore Query String would serve the same cached page for both — showing page 2 to users requesting page 3.
"Always Online™ serves my latest content during downtime"
Reality: Always Online™ serves a copy from the Internet Archive's Wayback Machine — which may be days, weeks, or even months old. It is a degraded fallback, not a live mirror of your site.
Anti-Patterns to Avoid
| Don't Do This | Do This Instead |
|---|---|
| Run "Purge Everything" after every deploy | Purge specific changed URLs; use hashed filenames for assets |
| Leave Development Mode on overnight | It auto-disables after 3 hrs, but disable manually and purge when done |
| Set Browser Cache TTL to 1 year on un-versioned HTML | Use short Browser TTL for HTML; use 1-year only for content-hashed assets |
| Use Ignore Query String on dynamic pages | Use Standard caching level; apply Ignore only via Cache Rule to specific static paths |
| Enable Always Online™ and think HA is solved | Implement load balancing, health checks, and a proper failover strategy |
Key Takeaways
- The Caching → Configuration page sets zone-wide defaults — Cache Rules can override these for specific paths.
- Caching Level: Standard is the safe default; use Ignore Query String only when query strings don't affect content.
- Browser Cache TTL controls how long the visitor's browser caches files — not purgeable from the dashboard.
- Purge targeted URLs rather than purging everything — it protects your origin from cold-start traffic spikes.
- Development Mode bypasses cache but does not purge it — always purge manually after a dev session.
- Always Online™ serves old Wayback Machine snapshots — it is a degraded fallback, not a high-availability solution.
- Crawler Hints improves search indexing speed — safe to enable on any site that benefits from fast re-indexing.
- CSAM Scanning is strongly recommended for any site with user-generated image uploads.
What's Next
- Return to Cache Rules to learn how to override these global defaults for specific URL patterns.
- Or continue to the next module: DDoS Protection.