---
description: Mark cached content as stale so Cloudflare revalidates it with your origin and reuses content that has not changed.
title: Invalidate cached content
image: https://developers.cloudflare.com/cache/guides/invalidate-cache/og.png?v=8651173c508c74fc
---

[Skip to content](#main-content)

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/cache/llms.txt  
> Use this file to discover all available pages before exploring further.

# Invalidate cached content

Last updated Sep 29, 2026|Copy as Markdown| [View as Markdown](https://developers.cloudflare.com/cache/guides/invalidate-cache/index.md)| [Agent setup](https://developers.cloudflare.com/agent-setup/)

Invalidation marks cached content as stale. On the next request, Cloudflare revalidates the content with your origin. If your origin responds with `304 Not Modified`, Cloudflare reuses the cached content instead of downloading it again.

Invalidation is sometimes called soft purge.

## Choose between purge and invalidation

Purge and invalidation accept the same selectors: URLs, cache tags, hostnames, URL prefixes, or everything. They differ in what happens to matching content:

| Behavior | Purge | Invalidate |
| --- | --- | --- |
| Cached content | Removed | Kept and marked as stale |
| Next request | Fetches the full response from your origin | Revalidates with your origin |
| Stale content | Not served | Can be served while revalidating or when your origin fails |
| API endpoint | `purge_cache` | `invalidate_cache` |

Use purge when cached content must not be served again. Update or remove the content at your origin before you purge it. Otherwise, the next request can cache the old version again.

Use invalidation to refresh content that might not have changed, such as a group of assets that share a cache tag.

## How invalidation works

Invalidation does not fetch new content in advance. Instead, the next request for invalidated content triggers revalidation.

To revalidate, Cloudflare sends your origin a conditional request. The request uses the `ETag` or `Last-Modified` header that your origin sent with the content. Your origin's response determines what happens next:

- If your origin responds with `304 Not Modified`, Cloudflare reuses the cached content and sets a new time to live (TTL).
- If your origin returns new cacheable content, Cloudflare replaces the cached content.
- If your origin returns a `5xx` error or cannot be reached, Cloudflare can serve the cached content stale. For details, refer to [Stale content during revalidation](#stale-content-during-revalidation).

Invalidation does not guarantee that content is reused. Cloudflare fetches the full response if the content is no longer cached, your origin sent neither header, or your origin does not support conditional requests.

A `304 Not Modified` response does not refresh cache tags set by [Cache Response Rules](https://developers.cloudflare.com/cache/how-to/cache-response-rules/). Cache tags from your origin's `Cache-Tag` header are updated only if your origin includes that header in the `304` response. To refresh cache tags otherwise, purge the content.

### Stale content during revalidation

Your cache settings and your origin's health determine whether visitors receive stale content while Cloudflare revalidates:

- With `stale-while-revalidate`, Cloudflare can serve stale content while it revalidates in the background.
- Without `stale-while-revalidate`, requests wait for revalidation to complete.
- If your origin returns a `5xx` error or cannot be reached, Cloudflare can serve stale content for as long as the content stays in cache. This happens even if the response has no `stale-if-error` directive. To limit this, set `stale-if-error` in the response. To prevent it, set `stale-if-error=0`. With [Origin Cache Control](https://developers.cloudflare.com/cache/concepts/cache-control/) enabled, `must-revalidate`, `proxy-revalidate`, and `s-maxage` also prevent it.

For content that is still fresh, `stale-while-revalidate` and `stale-if-error` windows start when you invalidate it, not when it would have expired. Invalidation never extends a stale window that has already ended.

For example, suppose you invalidate a cached response with the following headers before it expires:

```http
Cache-Control: public, max-age=3600, stale-while-revalidate=30
ETag: "product-v1"
```

Cloudflare can serve this response stale for up to 30 seconds after the invalidation while it revalidates. The response has no `stale-if-error` directive. If your origin returns a `5xx` error or cannot be reached, Cloudflare can serve the response stale beyond those 30 seconds. It can do so for as long as the response stays in cache.

Other directives and Cache Rules settings can prevent Cloudflare from serving stale content while it revalidates. For details, refer to [Revalidation](https://developers.cloudflare.com/cache/concepts/revalidation/).

### Cache Reserve

Invalidation keeps matching content in [Cache Reserve](https://developers.cloudflare.com/cache/advanced-configuration/cache-reserve/), where it continues to incur storage costs. If your origin responds with `304 Not Modified`, Cloudflare reuses the stored content instead of fetching it from your origin again. Content served from Cache Reserve is not served stale while it revalidates, even with `stale-while-revalidate`.

Compared with purging, invalidation reduces origin egress but not Cache Reserve operations. Updating the stored content after a `304` response is a Class A operation. Invalidating by URL also updates the stored content when you send the request, which is a Class A operation. For details, refer to [Cache Reserve operations](https://developers.cloudflare.com/cache/advanced-configuration/cache-reserve/#operations).

Purge forces a cache miss for matching Cache Reserve content. For details, refer to [Cache Reserve purge behavior](https://developers.cloudflare.com/cache/advanced-configuration/cache-reserve/#purge-behavior).

### Workers Cache

Invalidation from the dashboard or the `invalidate_cache` endpoint does not affect [Workers Cache](https://developers.cloudflare.com/workers/cache/). Workers Cache belongs to your Worker, not to your zone. To remove responses from a Worker's cache, call [`ctx.cache.purge()`](https://developers.cloudflare.com/workers/cache/purge/) from the Worker.

## Before you begin

Check the following requirements before you invalidate content:

- **Origin validators**: To reuse cached content, your origin must return an `ETag` or `Last-Modified` header and support conditional requests.
- **Permissions**: For API requests, use a token with the **Cache Purge** permission for the zone. To invalidate from the dashboard, your role must include the same permission.
- **Rate limits**: Invalidation requests count toward the purge limits for your account. For details, refer to [Limits](#limits).

## Invalidate using the dashboard

1. In the Cloudflare dashboard, go to the **Configuration** page. [Go to **Configuration** ↗](https://dash.cloudflare.com/?to=/:account/:zone/caching/configuration)
2. If your zone uses [Version Management](https://developers.cloudflare.com/version-management/), select the **Global** tab. Then, in **Invalidate Cache**, choose the environment under **Choose the environment**. The dashboard preselects an environment, so check the selection before you continue.
3. In **Invalidate Cache**, select **Custom Invalidation**. If your zone uses Version Management, this button is labeled **Select Content**.
4. Under **Select content by**, choose **URL**, **Hostname**, **Tag**, or **Prefix**, and enter the values to invalidate.
5. Select **Invalidate**.

To invalidate all cached content, select **Invalidate Everything**, and then confirm.

If your zone uses Version Management, **Invalidate Everything** is not available. Instead, choose **Everything: All cached content** under **Select content by**, and then select **Invalidate**. The dashboard does not ask you to confirm this option. Invalidating everything in the Production environment applies to all environments.

If your [cache key](https://developers.cloudflare.com/cache/how-to/cache-keys/) includes the visitor's device type or country, Enterprise zones can invalidate those variants of a URL from the dashboard. Select **URL**, and then set the device type or country under **Advanced (custom cache keys)**. For other cache key headers, use the API.

## Invalidate using the API

To invalidate content, send a `POST` request to the `invalidate_cache` endpoint:

```txt
https://api.cloudflare.com/client/v4/zones/{zone_id}/invalidate_cache
```

The request body uses the same format as the corresponding [purge request](https://developers.cloudflare.com/api/resources/cache/methods/purge/). The endpoint determines whether Cloudflare purges or invalidates the content.

In the following examples, replace `$ZONE_ID` with your [zone ID](https://developers.cloudflare.com/fundamentals/account/find-account-and-zone-ids/) and `$CLOUDFLARE_API_TOKEN` with your [API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/).

### Invalidate by URL

To invalidate specific URLs, list them in `files`:

```bash
curl --request POST \
  "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/invalidate_cache" \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "files": ["https://www.example.com/images/product.jpg"]
  }'
```

If your [cache key](https://developers.cloudflare.com/cache/how-to/cache-keys/) includes request headers, include the header values that identify the cached variant:

```json
{
	"files": [
		{
			"url": "https://www.example.com/images/product.jpg",
			"headers": {
				"CF-Device-Type": "desktop",
				"CF-IPCountry": "US"
			}
		}
	]
}
```

For URL matching requirements, refer to [Purge by single-file](https://developers.cloudflare.com/cache/how-to/purge-cache/purge-by-single-file/).

### Invalidate by tag, hostname, prefix, or everything

Use the request body that matches the content you want to invalidate:

| Selector | Request body |
| --- | --- |
| Cache tags | `{"tags":["product-images"]}` |
| Hostnames | `{"hosts":["images.example.com"]}` |
| URL prefixes | `{"prefixes":["www.example.com/images"]}` |
| Everything | `{"purge_everything":true}` |

Prefixes include a hostname and path, without a URL scheme.

For example, to invalidate all content tagged `product-images`, send this request:

```bash
curl --request POST \
  "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/invalidate_cache" \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{"tags":["product-images"]}'
```

Invalidating everything can trigger revalidation for a large amount of content as requests arrive. Select the smallest set of content that meets your needs.

### Invalidate content in an environment

For a non-production [Version Management](https://developers.cloudflare.com/version-management/) environment, include the environment ID in the path:

```bash
curl --request POST \
  "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/environments/$ENVIRONMENT_ID/invalidate_cache" \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{"tags":["product-images"]}'
```

To find the environment ID, refer to [Purge zone versions via API](https://developers.cloudflare.com/cache/how-to/purge-cache/purge-zone-versions/). For production, use the zone-level endpoint.

A request to invalidate everything in a non-production environment applies only to that environment. The same request to the zone-level endpoint applies to all environments.

## Limits

Invalidation requests count toward the same account-level [purge limits](https://developers.cloudflare.com/cache/how-to/purge-cache/#availability-and-limits) as purge requests. The limits that apply depend on how you select content:

| Selector | Limits that apply |
| --- | --- |
| URLs | [Single-file purge limits](https://developers.cloudflare.com/cache/how-to/purge-cache/#single-file-purge-limits) |
| Cache tags, hostnames, URL prefixes, or everything | [Hostname, tag, prefix URL, and purge everything limits](https://developers.cloudflare.com/cache/how-to/purge-cache/#hostname-tag-prefix-url-and-purge-everything-limits) |

Purge and invalidation requests draw from the same limits. Heavy use of one reduces the capacity available for the other. Like purge limits, these limits apply per account and are shared by zones on the same plan.

Each invalidation request can include the same maximum number of items as a purge request.

## Verify an invalidation

To verify an invalidation, use a cacheable test URL whose origin returns an `ETag` or `Last-Modified` header. Keep the content unchanged at your origin during the test. To observe revalidation directly, omit `stale-while-revalidate` from the test response and set a positive TTL.

1. Request the test URL until the `CF-Cache-Status` header returns `HIT`.
2. Invalidate the URL.
3. Request the URL again and check its response headers:

   ```bash
   curl --silent --show-error --dump-header - --output /dev/null \
     "https://www.example.com/images/product.jpg"
   ```


4. In your origin logs, confirm that Cloudflare sent a conditional request and that your origin returned `304`.

For cached content, expect the following results:

| Result | `CF-Cache-Status` |
| --- | --- |
| Your origin confirms that the content has not changed | `REVALIDATED`, then `HIT` |
| Your origin returns new content | `EXPIRED`, then `HIT` |
| Your origin sends no `ETag` or `Last-Modified` header | `EXPIRED`, then `HIT` |
| Cloudflare serves stale content while revalidating | `UPDATING`, then `HIT` |
| Your origin returns a `5xx` error or cannot be reached | `STALE` |
| The content is no longer cached | `MISS` |

Without an `ETag` or `Last-Modified` header from your origin, Cloudflare has nothing to revalidate with, so it fetches the full response. When your origin returns `304`, Cloudflare can still return `200 OK` to the visitor with the cached content.

With [Tiered Cache](https://developers.cloudflare.com/cache/how-to/tiered-cache/), a lower-tier data center revalidates with its upper-tier data center. A visitor can see `EXPIRED` or `MISS` even when your origin returned `304`. Concurrent requests can also affect which status you observe. Use your origin logs to confirm revalidation. For status definitions, refer to [Cloudflare cache responses](https://developers.cloudflare.com/cache/concepts/cache-responses/).

## Troubleshoot invalidation

### Your origin returns full responses

Confirm that the content was cached and that your selectors match it. Also confirm that your origin returns an `ETag` or `Last-Modified` header and responds to conditional requests with `304 Not Modified`.

Check these headers in a request sent directly to your origin, not through Cloudflare. When your origin sends neither header, responses from Cloudflare can still include a `Last-Modified` header because of [smart revalidation towards users](https://developers.cloudflare.com/cache/concepts/revalidation/#smart-revalidation-towards-users). Cloudflare does not use that header when it revalidates with your origin.

If the content was also purged after it was cached, the purge takes precedence, and the next request fetches the full response.

### Visitors receive stale content

While Cloudflare revalidates, it serves stale content only if the cached response includes `stale-while-revalidate`. You can turn this off with the [Serve stale content while revalidating](https://developers.cloudflare.com/cache/how-to/cache-rules/settings/#serve-stale-content-while-revalidating) setting in Cache Rules.

If your origin returns a `5xx` error or cannot be reached, Cloudflare serves invalidated content stale by default, for as long as it stays in cache. The Cache Rules setting does not change this. To limit how long Cloudflare serves stale content when your origin fails, set `stale-if-error` in your origin responses. To prevent it, set `stale-if-error=0`. With [Origin Cache Control](https://developers.cloudflare.com/cache/concepts/cache-control/) enabled, `must-revalidate`, `proxy-revalidate`, and `s-maxage` also prevent it.

To stop serving cached content, [purge](https://developers.cloudflare.com/cache/how-to/purge-cache/) it instead.

Was this helpful?

YesNo

## On this page

[![](https://developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/cache/guides/invalidate-cache/#page","headline":"Invalidate cached content","description":"Mark cached content as stale so Cloudflare revalidates it with your origin and reuses content that has not changed.","url":"https://developers.cloudflare.com/cache/guides/invalidate-cache/","inLanguage":"en","image":"https://developers.cloudflare.com/cache/guides/invalidate-cache/og.png?v=8651173c508c74fc","dateModified":"2026-09-29","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
