Why Isn’t My Cloudflare Cache Purge Working?

The purge almost certainly worked. The question is what it worked on — because a purge removes one exact cache key, and there are several ways to end up looking at a different one.

Updated August 22, 2026 · 7 min read

A purge clears one exact cache key. If the key you purged is not the key that is cached — a custom cache key, a transformed URL, a copy already sitting in a browser — the old file survives, and nothing looks wrong.

Cloudflare’s purge is not a background job that slowly rolls out. It is instant and global: by the time the dashboard confirms it, every data centre has dropped its copy. So “purge is not working” is nearly always one of two other things — the purge matched nothing, or the stale copy you are looking at was never Cloudflare’s to delete.

First, read the header rather than the page

A refreshed browser tab is the worst diagnostic available. Ask the edge directly instead:

curl -sSI https://example.com/app.css | grep -i '^cf-cache-status\|^age'

Each purge method leaves a documented fingerprint in cf-cache-status, and that fingerprint tells you whether the object was touched at all:

  • MISS — the object was deleted and refetched. This is what a URL, hostname, prefix or tag purge produces.
  • EXPIRED — the object was found but treated as stale, so it was revalidated against your origin. This is what Purge Everything produces.
  • HIT with a large Age — nothing happened. The object you are hitting is not the object you purged, which is the case the rest of this page is about.

The five purge methods, and what each one covers

MethodClearsStatus afterWatch out for
By URLOne exact URLMISSNo wildcards; case-sensitive path; misses custom cache keys from the dashboard
By prefixEverything under a pathMISSMax 31 path separators, 100 prefixes per request; query strings not supported
By hostnameEvery asset on one hostMISSUp to 100 hostnames per request
By cache tagEverything tagged at the originMISSRequires a Cache-Tag response header; up to 100 tags per request
Purge EverythingThe whole zoneEXPIREDSends every subsequent request back to your origin at once

One widely repeated claim is worth correcting: purge by tag, hostname and prefix are available on every plan, Free included. What differs by plan is the rate limit — five purge requests per minute on Free, up to fifty per second on Enterprise, counted per account rather than per zone.

Where a stale copy can still be sitting

What a Cloudflare cache purge reachesVisitor’s browserout of reach — expires on browser TTLWHAT A PURGE CLEARSEdge cacheevery data centre, all at onceUpper tieronly if Tiered Cache is onCache Reservedeleted by URL purge, revalidated by the restYour origin serveralways has the current filerefetched on next request
A purge empties Cloudflare’s copies. The copy already sitting in a browser is not Cloudflare’s to remove.

Reason one: the purge never matched the object

Cloudflare stores an object under a cache key, and a purge request is matched against that key. If your cache key includes headers or cookies, the dashboard cannot reproduce it — the form has nowhere to put those values — so a single-file purge from the dashboard silently matches nothing. The purge API accepts a headers object for exactly this reason, and any header you omit is treated as empty. The same applies to objects cached with an Origin, X-Forwarded-Host, X-Host, X-Forwarded-Scheme, X-Original-URL, X-Rewrite-URL or Forwarded request header: the dashboard cannot clear them, the API can.

Three more mismatches that produce the same silent no-op:

  1. Transform Rules, purged from the wrong side. If a Transform Rule rewrites the path, a single-file purge needs the end-user URL, while a prefix purge needs the post-transform origin URL. Using one convention for both is a common way to purge nothing twice.
  2. A Cache Rule that only matches GET. A purge arrives as a PURGE request, so an expression such as http.request.method eq "GET" excludes it. Widen the expression to accept PURGE as well, or purge by prefix or tag instead. Rules matching on fields that do not exist during a purge — a bot score, for instance — cannot be single-file purged at all.
  3. Wildcards. They are not supported in single-file purge. A URL with a query string has to be purged exactly as cached, or reached with prefix, hostname or tag purge.

Reason two: the edge is clean, the browser is not

This is the most common false alarm, and the documentation is unambiguous about it: purging Cloudflare’s cache does not affect assets stored by a visitor’s browser. Those copies live under the Cache-Controllifetime they were served with, and Cloudflare’s default Browser Cache TTL is four hours. You purge, you reload, you see the old file — from your own disk.

Confirm it with curl, or a private window, before touching anything at the edge again. The durable fix is not a shorter browser TTL but a changing filename: fingerprinted assets such as app.9f2c1d.css are never stale, because a new build is a new URL that no cache has ever seen.

Reason three: a layer below the edge still holds it

Two features move copies out from under a straightforward purge. With Tiered Cache enabled, a hostname, prefix or tag purge can return EXPIRED rather than MISS, because the lower tier revalidates against the upper tier instead of going straight to your origin. That is working as designed — but if your origin change was not picked up, the tier you reached is the one to check.

Cache Reserve is the sharper edge. A purge by URL removes the object from Cache Reserve along with the edge cache. Every other method — tag, hostname, prefix, and Purge Everything — only forces a revalidation attempt against what Cache Reserve holds, and Purge Everything is documented as a soft purge that does not refresh metadata such as cache tags. If you are on Cache Reserve and you need an object genuinely gone, purge it by URL.

Development Mode is not a purge

Development Mode suspends edge caching and Polish for three hours. It is the right tool while you are iterating on CSS, and the wrong tool for shipping a change: it deletes nothing, so when it expires, the objects cached beforehand are still there. If you need a longer bypass, use the bypass cache setting in Cache Rules instead, which is scoped to an expression rather than to the whole zone.

The habit that avoids all of this

Cloudflare recommends single-file purging over Purge Everything for a practical reason: after a full purge, every request in flight goes back to your origin at once. On a quiet site that is invisible; on a busy one it turns a copy edit into a traffic spike, and the slow origin responses that follow look like Cloudflare being broken.

A deploy sequence that never needs a purge at all:

  1. Fingerprint anything versioned — CSS, JS, images — so new builds get new URLs.
  2. Tag what cannot be fingerprinted with a Cache-Tag response header, then purge by tag when it changes.
  3. Reserve Purge Everything for configuration mistakes, not for releases.
  4. Verify with cf-cache-status rather than with a reload, and check from a private window when the header says MISS but the page still looks old.

If the header keeps saying DYNAMIC or BYPASS instead, the object was never cached and there is nothing to purge — that is a different problem with a different fix.

FAQ

How long does a Cloudflare cache purge take to work?

The purge itself is instant — Cloudflare calls it Instant Purge, and it applies across every data centre rather than rolling out region by region. If content is still old a minute later, the purge did not match the cached object, or what you are looking at is not Cloudflare's copy.

Does purging the Cloudflare cache clear my visitors' browser cache?

No. Purging removes Cloudflare's copies only, and the documentation states plainly that it does not affect assets stored by a visitor's browser. Those copies expire on the Browser Cache TTL that was sent with them, which defaults to four hours.

Why does my file still return cf-cache-status: HIT after I purged it?

Because the object being served is stored under a different cache key than the one you purged. Custom cache keys built from headers or cookies cannot be purged from the dashboard, and objects cached with an Origin or X-Forwarded-Host header need an API purge that includes those header values.

Is purge by cache tag only available on Enterprise plans?

Not any more. Cloudflare's availability table lists URL, hostname, tag, prefix and purge everything on Free, Pro, Business and Enterprise alike. What changes by plan is the rate limit: Free allows five purge requests per minute, while Enterprise allows fifty per second.

Should I use Purge Everything or purge by URL?

Purge by URL, in nearly every case. Cloudflare explicitly recommends single-file purging, because purging everything sends every subsequent request back to your origin at once, which on a busy site turns a content update into a traffic spike.

Does turning on Development Mode clear the cache?

No. Development Mode suspends edge caching and Polish for three hours so you can see origin changes immediately, but it removes nothing that is already cached. When it switches off, the old objects are still there unless they expired in the meantime.

Manage this from your phone

Orange Cloud is a native iOS and Android client for Cloudflare. Sign in with Cloudflare OAuth and flip proxy status, edit DNS records, and read traffic analytics from anywhere.

Get Orange Cloud