
September 08, 2026
11 min read
By Kokil Thapa | Last reviewed: September 2026
Your mobile app calls POST /api/v1/orders and gets a cached 200 OK from yesterday. That is what happens when Cloudflare DNS cache bypass for API endpoints is misconfigured — or never configured at all. Cloudflare sits in front of most production stacks I maintain, including Laravel REST APIs for Nepal clients and international eCommerce backends. The fix is not one toggle. You combine DNS record mode, edge Cache Rules, and origin Cache-Control headers so dynamic API traffic always reaches PHP, Node, or your gateway unchanged.
Cache-Control: private, no-store, so JSON, auth tokens, and mutation responses never serve from the edge.What is Cloudflare DNS cache bypass for API endpoints?
Search results mix up three layers. Clarify them before you change anything in the dashboard.
- DNS resolver cache — TTL on A/AAAA/CNAME records. Clients and resolvers cache where
api.example.compoints. This is not HTTP response caching. - Cloudflare edge HTTP cache — When the orange cloud (proxied) is on, Cloudflare can store GET responses at 300+ PoPs worldwide. This is what breaks APIs.
- Origin application cache — Redis, Laravel route cache, or Memcached on your server. Separate problem, same symptom: stale data.
This article focuses on layer two plus DNS routing choices that affect whether layer two applies at all. On a legal-tech portal I built, a proxied api. subdomain once cached a GET profile endpoint because the Laravel controller returned no Cache-Control header. The browser was fine; Cloudflare was not.
When people say "DNS cache bypass," they usually mean one of two things: put the API hostname on DNS-only (grey cloud), or keep it proxied but tell Cloudflare never to cache HTTP responses. Both are valid. The wrong choice depends on whether you still want DDoS protection, WAF, and Bot Fight Mode on that hostname.
How do you configure Cloudflare to bypass cache for API routes?
Cloudflare replaced most Page Rules with Cache Rules and Configuration Rules. For a Laravel 13 or Symfony 8.1 API behind Cloudflare in 2026, this is the order I use on production deploys.
Step 1: Split API traffic onto a dedicated hostname
Never mix HTML and JSON on the same hostname unless you enjoy debugging. A clean pattern:
www.example.com— proxied, cached static assetsapi.example.com— proxied with bypass rules, or grey-cloud
This mirrors what I do on booking systems like trek management APIs with Livewire frontends. The public site gets full CDN benefit; the API gets protection without stale JSON.
Step 2: Create a Cache Rule that bypasses the edge
In Cloudflare Dashboard → Caching → Cache Rules, add a rule:
- Rule name:
Bypass API cache - When incoming requests match: Hostname equals
api.example.comOR URI Path starts with/api/ - Then: Cache eligibility → Bypass cache
For path-based rules on a shared hostname, match http.request.uri.path starts with /api/. That covers /api/v1/users without touching /blog/ pages on the same domain.
Step 3: Disable cache for non-GET methods via Configuration Rules
Cloudflare should never cache POST, PUT, PATCH, or DELETE. Default behaviour usually respects this, but explicit rules remove doubt during audits. Add a Configuration Rule: if method is not GET or HEAD, set cache to bypass.
Step 4: Set origin response headers
Edge rules are not enough if your origin sends Cache-Control: public, max-age=3600 on a user profile endpoint. Laravel example in app/Http/Middleware/NoCacheApi.php:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class NoCacheApi
{
public function handle(Request $request, Closure $next)
{
$response = $next($request);
return $response->header('Cache-Control', 'private, no-store, no-cache, must-revalidate')
->header('Pragma', 'no-cache')
->header('Expires', '0');
}
}
Register it on your API route group in bootstrap/app.php (Laravel 13) or app/Http/Kernel.php (Laravel 12). See Laravel API best practices for middleware ordering with Sanctum auth.
Official reference: Cloudflare documents Cache Rules at developers.cloudflare.com/cache/how-to/cache-rules/. Treat that page as the source of truth when field names change between dashboard versions.
Should API subdomains use proxied or DNS-only Cloudflare records?
This is the main architectural fork. Both achieve cache bypass; they differ on security and ops burden.
| Criteria | Proxied (orange cloud) + Bypass rules | DNS-only (grey cloud) |
|---|---|---|
| Edge HTTP cache | Bypassed via Cache Rules | Not applicable — traffic skips CDN cache layer |
| DDoS / WAF protection | Full Cloudflare proxy protection | Origin IP exposed; protect elsewhere |
| SSL mode | Flexible, Full, or Full (Strict) | Direct cert on origin only |
| Rate limiting | Cloudflare Rate Limiting rules work | Must use app-level or gateway limits |
| Typical use case | Public REST APIs, mobile backends | Internal webhooks, admin-only APIs |
My default for client-facing APIs: keep api. proxied and bypass cache. Grey-cloud only when the client runs their own Kong or Traefik gateway with separate DDoS coverage, or when debugging origin connectivity. Exposing origin IP on a grey-cloud API record invites direct attacks past Cloudflare — I have seen this on shared hosting where the IP leaked through historical DNS records anyway.
For RESTful Laravel APIs with Sanctum cookie auth, proxied mode also lets you use Cloudflare Transform Rules to normalize headers. DNS-only means you lose that edge tooling.
What Cache-Control headers should APIs send behind Cloudflare?
Cloudflare respects origin cache directives unless a Cache Rule overrides them. For APIs, be explicit and boring.
Dynamic JSON endpoints (default)
Cache-Control: private, no-store, no-cache, must-revalidate
Pragma: no-cache
private tells shared caches not to store the response. no-store is stronger — do not store anywhere. Use both on authenticated routes and any endpoint returning user-specific data.
Read-only public GET you intentionally cache
Some catalogue or reference endpoints can sit at the edge. Example: a public product list with a five-minute TTL.
Cache-Control: public, max-age=300, s-maxage=300
Then add a separate Cache Rule: cache eligible only when path matches /api/v1/products and method is GET. Everything else bypasses. This split appears on Laravel eCommerce projects with delivery-zone APIs where product lists are cacheable but cart endpoints are not.
Strip misleading headers from upstream packages
Some PHP frameworks or reverse proxies add ETag or default caching on error pages. Audit with:
curl -sI "https://api.example.com/api/v1/health" | grep -iE 'cache|cf-|age|etag'
You want cf-cache-status: BYPASS or DYNAMIC on dynamic routes. HIT on a user-specific JSON response is a production incident waiting for peak traffic.
The HTTP caching spec lives in RFC 9111. Cloudflare's interpretation is documented under their cache behaviour guides — cross-check when upgrading from Page Rules legacy setups described in Cloudflare CDN setup and best practices.
How do you verify API responses are not cached at the edge?
Verification belongs in every deploy checklist, not only after an incident. I run these checks after Deployer 7 symlink swaps on sister sites sharing GitLab CI pipelines.
Check CF-Cache-Status on every critical route
- Call the endpoint with
curl -sIand readCF-Cache-Status. - Repeat with a unique query string:
?t=1699999999— status should still be BYPASS or DYNAMIC, not HIT. - POST the same URL with a body. Confirm no
Ageheader grows between calls. - Test from two regions if you have colleagues abroad — edge PoP behaviour can differ slightly.
Use the JSON formatter tool to inspect response bodies when comparing cached versus fresh payloads side by side during debugging.
Purge is not a strategy
Teams sometimes hit "Purge Everything" after API deploys. That nukes your marketing site cache too. Purge by URL or tag only for static assets. API bypass rules remove the need for routine purges entirely.
Watch for Authorization header quirks
By default Cloudflare may not vary cache keys on Authorization. Two users hitting the same cacheable URL could theoretically share a cached body if you accidentally left caching on. Bypass rules sidestep this. For cookie-based Sanctum APIs, see Passport vs Sanctum authentication patterns — SPA cookie flows need credentials: include and correct CORS, independent of cache settings.
What common mistakes break API cache bypass on Cloudflare?
These show up repeatedly on support and maintenance engagements when a site "worked in staging" without the orange cloud enabled.
- Staging DNS-only, production proxied — Cache bugs appear only after go-live. Mirror Cloudflare settings across environments.
- Wildcard Page Rules conflicting with Cache Rules — Legacy "Cache Everything" on
*example.com/*overrides newer rules. Delete old Page Rules first. - Flexible SSL with POST bodies — Not a cache issue, but mixed setups mask real errors. Use Full (Strict) with a valid origin cert from Let's Encrypt.
- Caching 404 and 500 responses — Add a rule to bypass cache when origin status is ≥ 400, or set short TTL on error pages.
- Forgetting webhooks — Payment callbacks from eSewa, Khalti, or Stripe must bypass cache and accept POST without challenge pages. Bot Fight Mode blocking webhooks is a separate rate-limit and firewall tuning task.
For multi-cloud setups where API DNS lives in Route 53 but HTTP proxy is Cloudflare, read cross-cloud DNS and traffic routing before changing TTL or CNAME chains. Low TTL during migration helps; raise it after cutover for resolver stability.
Webhook idempotency matters too — cached duplicate delivery responses can mask retry logic bugs. Pair bypass rules with idempotency key patterns on mutation endpoints.
Key Takeaways
- Cloudflare DNS cache bypass for API endpoints means stopping edge HTTP caching — use Cache Rules with "Bypass cache" on
api.hostnames or path prefixes. - Prefer proxied (orange cloud) API records plus bypass rules over grey-cloud unless you accept exposed origin IP and lost WAF.
- Always send
Cache-Control: private, no-storefrom Laravel, Symfony, or your API framework on dynamic routes. - Verify with
curl -sIand confirmCF-Cache-Status: BYPASS— never ship after "Purge Everything" alone. - Split cacheable public GET catalogues from uncacheable auth and cart routes using separate Cache Rules, not one global bypass.
- Align staging and production Cloudflare proxy settings so cache bugs surface before launch, not on Dashain traffic spikes.
People Also Ask
Does Cloudflare cache POST requests to API endpoints?
No — Cloudflare does not cache POST, PUT, PATCH, or DELETE by default. Problems usually come from GET endpoints that return JSON without Cache-Control headers, or from legacy Page Rules set to Cache Everything. Fix with Cache Rules set to Bypass cache on your API hostname.
What is the difference between BYPASS and DYNAMIC in CF-Cache-Status?
BYPASS means Cloudflare skipped cache lookup because of a rule or request header. DYNAMIC means the response was not eligible for caching but still went through the proxy. Both are acceptable for dynamic APIs. HIT on authenticated JSON is the red flag.
Should I use a separate subdomain for API traffic?
Yes — api.example.com simplifies Cache Rules, TLS cert management, and DNS record organisation. You can apply WAF rules specific to JSON traffic without affecting the marketing site cache policy.
Can I cache some API GET responses but not others?
Yes. Create multiple Cache Rules ordered from most specific to least. Example: cache /api/v1/products GET for 300 seconds; bypass everything else on the same hostname. Your origin must send matching Cache-Control headers for cacheable routes only.
Ship APIs that stay fresh behind Cloudflare
Cloudflare DNS cache bypass for API endpoints is a three-part job: correct DNS proxy mode, edge Cache Rules, and origin headers that agree. Skip any leg and you will chase phantom bugs — stale orders, wrong user profiles, webhook retries that look successful but are not. I configure this on every API project before load testing, alongside speed work on cacheable static assets so you keep CDN wins without sacrificing API correctness.
If your API returns CF-Cache-Status: HIT on routes that should be dynamic, contact us for a Cloudflare and Laravel audit. You can also browse the portfolio for production APIs behind Cloudflare, or read API monitoring with Prometheus and Grafana to catch cache regressions in CI.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

