Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Cloudflare DNS Cache Bypass for API Endpoints

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.

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.com points. 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.

Three Caching Layers for API TrafficDNS ResolverTTL on A/CNAMECloudflare EdgeHTTP GET cacheOrigin AppRedis / LaravelAPI bypass target: Cloudflare edge HTTP cacheUse grey-cloud DNS or Cache Rules: BypassPlus Cache-Control: private, no-store on origin
Cloudflare DNS cache bypass for API endpoints targets edge HTTP caching — not resolver TTL alone.

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 assets
  • api.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 → CachingCache Rules, add a rule:

  1. Rule name: Bypass API cache
  2. When incoming requests match: Hostname equals api.example.com OR URI Path starts with /api/
  3. 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.

Cache Rule Pipeline for api.example.comClientCloudflareCache RuleOriginPHP / LaravelResponseRule: Host eq api.example.comAction: Bypass cacheOrigin sends Cache-Control: no-storeCF-Cache-Status: BYPASS on every request
Configure Cloudflare Cache Rules so API requests always reach your origin server.

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.

CriteriaProxied (orange cloud) + Bypass rulesDNS-only (grey cloud)
Edge HTTP cacheBypassed via Cache RulesNot applicable — traffic skips CDN cache layer
DDoS / WAF protectionFull Cloudflare proxy protectionOrigin IP exposed; protect elsewhere
SSL modeFlexible, Full, or Full (Strict)Direct cert on origin only
Rate limitingCloudflare Rate Limiting rules workMust use app-level or gateway limits
Typical use casePublic REST APIs, mobile backendsInternal 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.

Proxied vs Grey-Cloud API DNSOrange Cloud + BypassWAF + DDoS + Rate limitsCache Rules requiredGrey Cloud DNS OnlyNo edge cache by designOrigin IP visibleRecommended: Proxied + Bypass cacheFor public mobile and SPA API consumersPair with Laravel rate limiting at origin
Compare proxied API subdomains with Cache Rules against grey-cloud DNS-only records.

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

  1. Call the endpoint with curl -sI and read CF-Cache-Status.
  2. Repeat with a unique query string: ?t=1699999999 — status should still be BYPASS or DYNAMIC, not HIT.
  3. POST the same URL with a body. Confirm no Age header grows between calls.
  4. 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.

Verify CF-Cache-Status on Deploycurl -sIRead headerBYPASS or DYNAMICFAIL: CF-Cache-Status HIT on POST or auth JSONFix: Cache RuleBypass on api hostFix: Origin headerCache-Control: no-store
Deployment verification flow for Cloudflare DNS cache bypass on API endpoints.

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-store from Laravel, Symfony, or your API framework on dynamic routes.
  • Verify with curl -sI and confirm CF-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

It stops Cloudflare edge HTTP caching on API traffic using Bypass cache rules and origin Cache-Control: private, no-store—not DNS resolver TTL alone.

Split API traffic onto api.example.com or a /api/ path prefix, then add a Cache Rule: hostname equals api.example.com or URI path starts with /api/, set Cache eligibility to Bypass cache. Add a Configuration Rule to bypass cache for non-GET methods. On Laravel 13 or Symfony 8.1, register middleware like NoCacheApi on your API route group to send Cache-Control: private, no-store, no-cache, must-revalidate plus Pragma: no-cache. Edge rules alone fail if your origin sends public max-age headers—both layers must agree.

Both achieve cache bypass but differ on security. Proxied orange-cloud records plus Bypass Cache Rules keep DDoS protection, WAF, Bot Fight Mode, and Cloudflare Rate Limiting active while skipping edge HTTP cache. DNS-only grey-cloud records skip the CDN cache layer entirely but expose your origin IP and remove edge tooling like Transform Rules. My default for client-facing REST APIs: keep api. proxied with bypass rules. Grey-cloud suits internal webhooks or when a separate Kong or Traefik gateway handles DDoS—but direct IP attacks become a real risk on shared hosting.

For dynamic JSON, authenticated routes, and user-specific data, send Cache-Control: private, no-store, no-cache, must-revalidate with Pragma: no-cache. private blocks shared caches; no-store is stronger and prevents storage anywhere. For intentionally cacheable public GET catalogues, use Cache-Control: public, max-age=300, s-maxage=300 and a separate Cache Rule matching only that path and GET method. Audit upstream packages stripping misleading ETag headers. Run curl -sI against health endpoints and grep for cache, cf-, age, and etag—you want cf-cache-status BYPASS or DYNAMIC on dynamic routes, never HIT on user JSON.

Add this to every deploy checklist, not only after incidents. Call critical routes with curl -sI and read CF-Cache-Status—repeat with a unique query string like ?t=timestamp; status should stay BYPASS or DYNAMIC, never HIT. POST the same URL with a body and confirm no Age header grows between calls. Test from two regions if possible since PoP behaviour varies slightly. Purge Everything is not a strategy—it nukes marketing site cache too. Bypass rules remove routine purge needs. Watch Authorization header quirks: Cloudflare may not vary cache keys on Authorization, so two users could share a cached body if caching was accidentally left on.

No—Cloudflare does not cache POST, PUT, PATCH, or DELETE by default. Stale API problems usually come from GET endpoints returning JSON without Cache-Control headers or legacy Page Rules set to Cache Everything.

BYPASS means Cloudflare skipped cache lookup due to a rule or request header. DYNAMIC means the response was not cache-eligible but still proxied through Cloudflare. Both are acceptable for dynamic APIs.

Yes. api.example.com simplifies Cache Rules, TLS certificate management, and DNS record organisation. You can apply WAF rules specific to JSON traffic without affecting your marketing site cache policy on www.example.com.

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: public, max-age=300, s-maxage=300 only on cacheable routes. This split appears on Laravel eCommerce projects where product lists are cacheable but cart and auth endpoints are not. Everything else gets private, no-store from middleware. One global bypass rule wastes CDN wins on safe read-only catalogues; one global cache rule breaks mutations and user profiles.

Staging DNS-only with production proxied hides cache bugs until go-live—mirror Cloudflare settings across environments. Wildcard legacy Page Rules like Cache Everything on example.com/ override newer Cache Rules; delete old Page Rules first. Flexible SSL with POST bodies masks real errors—use Full Strict with a valid Let's Encrypt origin cert. Cloudflare can cache 404 and 500 responses unless you bypass cache on origin status ≥ 400. Forgetting webhooks is common: payment callbacks from eSewa, Khalti, or Stripe must bypass cache and accept POST without challenge pages. Bot Fight Mode blocking webhooks is a separate firewall tuning task.

POST itself is not cached, but the symptom often traces to a related GET—profile, order status, or cart—served from edge cache without Cache-Control headers. On a legal-tech portal I built, a proxied api. subdomain cached a GET profile endpoint because the Laravel controller returned no Cache-Control header. The browser was fine; Cloudflare was not. Fix the three-part stack: Cache Rule bypass on api. hostname, Configuration Rule for non-GET methods, and origin middleware sending private, no-store. Verify with curl -sI and confirm CF-Cache-Status is not HIT on dynamic JSON.

Yes. Cloudflare replaced most Page Rules with Cache Rules and Configuration Rules. For Laravel 13 or Symfony 8.1 APIs in 2026, use Caching → Cache Rules with Bypass cache eligibility matched on hostname or URI path prefix. Legacy Cache Everything Page Rules on wildcards actively conflict with and override newer rules—I delete old Page Rules before auditing new Cache Rules. Official field names live at developers.cloudflare.com/cache/how-to/cache-rules/; treat that page as source of truth when dashboard labels change between versions.

Payment callbacks from eSewa, Khalti, IME Pay, ConnectIPS, or Stripe must bypass edge cache and accept POST without Bot Fight Mode challenge pages. Cached duplicate delivery responses can mask retry logic bugs—pair bypass rules with idempotency keys on mutation endpoints. Add explicit Cache Rules bypassing your webhook path prefix and confirm CF-Cache-Status on test POSTs. Webhook idempotency matters because a cached 200 from a previous delivery makes retries look successful when origin logic never ran. Rate limiting and firewall tuning for webhooks is separate from cache config but equally critical on proxied API records.

Cache bugs appear only after go-live when staging runs DNS-only grey-cloud but production enables the orange cloud. I've seen this repeatedly: APIs work in staging, then stale orders and wrong user profiles surface on traffic spikes. Mirror proxy mode, Cache Rules, and Configuration Rules across environments before load testing. Run curl -sI checks against staging with the same hostname pattern you will use in production—api.staging.example.com proxied with bypass rules, not grey-cloud unless production will match. Align settings before Dashain or peak booking season, not during incident response.

It is a production incident waiting for peak traffic. HIT means Cloudflare served that response from edge cache instead of your origin PHP or Node server. On authenticated routes returning user-specific JSON, you should see BYPASS or DYNAMIC only. Causes include missing Cache-Control headers on Laravel controllers, legacy Cache Everything Page Rules, or a Cache Rule that accidentally enables caching on /api/ paths. Fix with Bypass cache rules on api. hostname, NoCacheApi middleware sending private, no-store, and deletion of conflicting Page Rules. Never ship after Purge Everything alone—that treats symptoms, not configuration.

Share this article

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.

Quick Contact Options
Choose how you want to connect me: