By default, Cloudflare only caches static assets (JS, CSS, images). To cache HTML pages, you need to create Cache Rules — this dramatically reduces server load.
What Cloudflare caches by default
Caching → Configuration → Caching Level: Standard caches files with extensions: .jpg, .png, .gif, .css, .js, .woff2, .ico, and other static formats.
Cache Rule for HTML pages
Caching → Cache Rules → Create rule:
# Cache all HTML pages (excluding /admin, /wp-admin)
Conditions:
- hostname equals example.com
- AND NOT path starts with /wp-admin
- AND NOT path starts with /admin
- AND NOT Cookie contains wordpress_logged_in
Cache Settings:
- Eligible for cache: Yes
- Edge TTL: 4 hours
- Browser TTL: 1 hour
Cache bypass for WordPress
# Cache Rule — BYPASS for WordPress admin
Conditions:
- Cookie contains: wordpress_logged_in
OR Path starts with: /wp-admin
OR Path starts with: /wp-login.php
Cache Settings:
- Cache Status: Bypass
Forced cache purge
Caching → Configuration → Purge Cache:
- Purge Everything — clears the entire cache (use with caution)
- Custom Purge — clears the cache for a specific URL
- Purge by Tag/Host/Prefix — Business plan and above
Cache Analytics
Caching → Cache Analytics — shows the ratio of HIT/MISS/BYPASS requests. Target: HIT rate > 80% for static assets.
Common Caching Problems
| Symptom | Cause |
|---|---|
| CF-Cache-Status: DYNAMIC instead of the expected HIT | The request doesn't match the Cache Rule conditions, or the response has a Set-Cookie header — Cloudflare doesn't cache such responses by default |
| CF-Cache-Status: EXPIRED right after a purge | The Edge TTL expired sooner than expected — check it against the origin's Cache-Control headers |
| A user sees someone else's cart or data | A personalized page was cached without a Cookie-based exclusion — a critical configuration mistake |
| Site changes don't appear even after Purge Everything | The culprit isn't Cloudflare but the browser cache or an intermediate cache on the hosting side (for example, a page in OPcache/Redis) |
Recommended TTLs by Content Type
| Content type | Edge TTL | Browser TTL |
|---|---|---|
| Static assets (JS/CSS/images) | 1 month | 1 day |
| Public page HTML | 4 hours | 10 minutes |
| API responses without personalization | 5 minutes | No cache (no-store) |
| Personalized pages | Bypass | No cache (no-store) |
When Cache Rules Won't Help
- Content is personalized per user (account area, cart) — such pages can't be cached at all without risking a data leak between users
- The site already sends correct Cache-Control headers and doesn't need to be overridden at the Cloudflare level
- The application depends on real-time data freshness (quotes, chats) — any caching here is harmful
- The Free plan limits the number of rules and condition types — complex logic needs a higher plan
Verifying the Result
After configuring a rule, confirm caching actually works using the response header:
curl -sI https://example.com/ | grep -i cf-cache-status
# The first request is usually MISS, a repeat within the Edge TTL should be HIT
curl -sI https://example.com/ | grep -i cf-cache-status
If the status is consistently DYNAMIC, check the conditions of your Page Rules: an old rule with higher priority can override the new Cache Rule. For general speed tips, see Cloudflare speed optimization.
Rule Evaluation Order
Cache Rules in Cloudflare run top to bottom, and the first rule whose conditions match wins — later rules aren't checked for that request. The practical takeaway: put more specific conditions (a particular path, a particular subdomain) above general ones, or the general rule will intercept the request before the system ever reaches the exact match.
This same behavior explains a common source of confusion, where an administrator adds a new narrow rule and it seems not to work — in reality, an earlier, broader rule is firing instead. You can check which rule actually applied under Caching → Cache Rules, using the "Requests" counter that updates as the site receives traffic.
Interaction With the Hosting's Own Cache
Cloudflare caches responses at edge servers worldwide, but that doesn't replace a separate cache on the hosting side — for example, a WordPress plugin's page cache or PHP OPcache. These two layers work independently: purging the Cloudflare cache doesn't touch the server-side cache, and vice versa. When debugging stale content, always check both layers separately, or you'll easily waste time "purging the wrong cache."