---
description: Delete cached responses with ctx.cache.purge() or mark them stale with ctx.cache.invalidate() — by tag, by path prefix, or everything.
title: Purge and invalidate the cache
image: https://developers.cloudflare.com/workers/cache/purge/og.png?v=232653489c14e903
---

[Skip to content](#main-content)

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

# Purge and invalidate the cache

Last updated Oct 3, 2026|Copy as Markdown| [View as Markdown](https://developers.cloudflare.com/workers/cache/purge/index.md)| [Agent setup](https://developers.cloudflare.com/agent-setup/)

Your Worker can delete its own cached responses at any time with `purge()`, or mark them stale with [`invalidate()`](#invalidate-cached-responses) so that the cache revalidates them with your Worker on the next request. Both are useful when data changes and the new value is more important than the performance benefit of continuing to serve the cached response — for example, after a content update, a user action, or a webhook from an upstream system.

Because Workers Caching is **your Worker's cache**, purging and invalidating are scoped to the Worker that owns the cache. Within a Worker, both are further scoped to the [entrypoint](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/rpc/#named-entrypoints) that called `purge()` or `invalidate()`. A Worker cannot reach into another Worker's cache, an entrypoint cannot reach into another entrypoint's cache, and no zone-level purge (via the dashboard, [API](https://developers.cloudflare.com/cache/how-to/purge-cache/), or Terraform) affects Workers Caching content.

## Two ways to call purge

There are two equivalent ways to trigger a purge from inside your Worker:

- **`ctx.cache.purge(...)`** — available on the execution context passed to every handler. Use this when you already have `ctx` in scope.
- **`cache.purge(...)`** — imported from `cloudflare:workers`. Use this when you want to call purge from code that does not receive `ctx` — for example, a utility module shared across multiple handlers, or a framework adapter that does not thread the execution context through its internals.

Both forms call into the same API and behave identically. Pick whichever reads more cleanly for your code.

*src/index.jsjs*

```js
import { cache } from "cloudflare:workers";

export default {
	async fetch(request, env, ctx) {
		// Using the module import — no need to thread ctx through helper functions.
		await cache.purge({ tags: ["blog-posts"] });

		// Equivalent, using ctx directly:
		// await ctx.cache.purge({ tags: ["blog-posts"] });

		return new Response("Purged", { status: 200 });
	},
};
```

*src/index.tsts*

```ts
import { cache } from "cloudflare:workers";

export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Using the module import — no need to thread ctx through helper functions.
		await cache.purge({ tags: ["blog-posts"] });

		// Equivalent, using ctx directly:
		// await ctx.cache.purge({ tags: ["blog-posts"] });

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;
```

The rest of this page uses `ctx.cache.purge(...)` in most examples because those examples already have `ctx` in scope. If you prefer the import form, substitute `cache.purge(...)` — nothing else changes.

## Purge modes

`purge()` accepts either `purgeEverything: true` on its own, or one or both of `tags` and `pathPrefixes`:

| Field | Purges | Scope |
| --- | --- | --- |
| `tags` | Every cached response tagged with one of the given values via `Cache-Tag`. | Per entrypoint |
| `pathPrefixes` | Every cached response whose request path starts with one of the given prefixes. | Per entrypoint |
| `purgeEverything` | Every cached response for the entrypoint that called `purge()`. | Per entrypoint |

`purgeEverything` is exclusive — combine `tags` and `pathPrefixes` in a single call if you want, but do not pass either alongside `purgeEverything`.

All three modes are scoped to the [entrypoint](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/rpc/#named-entrypoints) that called `purge()`. A purge from `PublicAPI` does not affect cached responses stored by `AdminAPI`, even if they share tag names or path prefixes. To purge across every entrypoint of a Worker, call `purge()` from each entrypoint.

The returned promise resolves to a result object you can inspect to confirm success or handle failures — see [Return value](#return-value).

Purge after a write by calling `ctx.cache.purge()` at the end of any handler that mutates data:

*src/index.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		if (request.method === "POST") {
			const body = await request.json();

			// Mutate your data source (D1, KV, an origin, and so on), then purge
			// every cached response tagged for this post.
			await ctx.cache.purge({
				tags: [`post-${body.postId}`, "post-list"],
			});

			return new Response("Updated", { status: 200 });
		}

		// Handle cacheable reads here.
		return new Response("Hello", {
			headers: { "Cache-Control": "public, max-age=3600" },
		});
	},
};
```

*src/index.tsts*

```ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		if (request.method === "POST") {
			const body = await request.json<{ postId: string }>();

			// Mutate your data source (D1, KV, an origin, and so on), then purge
			// every cached response tagged for this post.
			await ctx.cache.purge({
				tags: [`post-${body.postId}`, "post-list"],
			});

			return new Response("Updated", { status: 200 });
		}

		// Handle cacheable reads here.
		return new Response("Hello", {
			headers: { "Cache-Control": "public, max-age=3600" },
		});
	},
} satisfies ExportedHandler;
```

You can combine fields in a single call. For example, `purge({ tags: ["blog-posts"], pathPrefixes: ["/blog/"] })` purges everything that matches **either** tag or path-prefix — the fields are unioned, not intersected. Use this when one logical change affects responses tagged by multiple schemes.

*src/index.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		// Combined call: purges everything tagged "blog-posts" AND
		// everything under /blog/ in a single round-trip.
		await ctx.cache.purge({
			tags: ["blog-posts"],
			pathPrefixes: ["/blog/"],
		});

		return new Response("Purged", { status: 200 });
	},
};
```

*src/index.tsts*

```ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Combined call: purges everything tagged "blog-posts" AND
		// everything under /blog/ in a single round-trip.
		await ctx.cache.purge({
			tags: ["blog-posts"],
			pathPrefixes: ["/blog/"],
		});

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;
```

## Purge by tag

Tags are attached to responses via the `Cache-Tag` response header, and purged later by name. This is the most flexible and commonly used purge method.

### Attach tags on write

*src/index.jsjs*

```js
export default {
	async fetch(request) {
		const url = new URL(request.url);
		const postId = url.pathname.split("/").pop() ?? "unknown";
		const body = { id: postId, title: `Post ${postId}` };

		return new Response(JSON.stringify(body), {
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": `post,post-${postId},blog`,
			},
		});
	},
};
```

*src/index.tsts*

```ts
export default {
	async fetch(request): Promise<Response> {
		const url = new URL(request.url);
		const postId = url.pathname.split("/").pop() ?? "unknown";
		const body = { id: postId, title: `Post ${postId}` };

		return new Response(JSON.stringify(body), {
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": `post,post-${postId},blog`,
			},
		});
	},
} satisfies ExportedHandler;
```

The `Cache-Tag` header value is a comma-separated list of tags. Cloudflare strips this header before returning the response to clients.

Tag values must be **printable ASCII** (no spaces, no Unicode), each tag is at most **1024 characters** long, and a response can carry up to **1000 tags**. Tag matching at purge time is **case-insensitive**, so `Foo` and `foo` purge the same set of responses. Invalid tags are silently dropped at storage time — the response is still cached with the remaining valid tags. Refer to [Cache tag limits](https://developers.cloudflare.com/cache/how-to/purge-cache/purge-by-tags/#a-few-things-to-remember) for the full list.

### Trigger the purge

*src/admin.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		const postId = new URL(request.url).searchParams.get("id");
		if (!postId) return new Response("Missing id", { status: 400 });

		await ctx.cache.purge({ tags: [`post-${postId}`] });

		return new Response("Purged", { status: 200 });
	},
};
```

*src/admin.tsts*

```ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		const postId = new URL(request.url).searchParams.get("id");
		if (!postId) return new Response("Missing id", { status: 400 });

		await ctx.cache.purge({ tags: [`post-${postId}`] });

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;
```

### Tag scope across entrypoints

Tags are scoped to the entrypoint that called `purge()`. A tag named `user-42` applied to responses in two different entrypoints is **not** purged by a single `purge({ tags: ["user-42"] })` call — it only affects the entrypoint the call originated from. If you need to purge the same tag across several entrypoints, call `purge()` from each entrypoint, or centralize purge calls in a shared entrypoint that caches every response you later need to purge.

### Use hierarchical tags

To purge groups of related responses in one call, tag each response with multiple tags representing every level of hierarchy it belongs to — sometimes called "soft tags":

*src/index.jsjs*

```js
export default {
	async fetch(request) {
		const path = new URL(request.url).pathname;

		// Build a list of hierarchical tags for the current path.
		// A response at /blog/2025/02/hello gets tags for:
		//   _path:/blog/, _path:/blog/2025/, _path:/blog/2025/02/, _path:/blog/2025/02/hello
		const segments = path.split("/").filter(Boolean);
		const tags = segments.map(
			(_, i) => `_path:/${segments.slice(0, i + 1).join("/")}/`,
		);

		const body = `<!doctype html><title>${path}</title>`;

		return new Response(body, {
			headers: {
				"Content-Type": "text/html",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": tags.join(","),
			},
		});
	},
};
```

*src/index.tsts*

```ts
export default {
	async fetch(request): Promise<Response> {
		const path = new URL(request.url).pathname;

		// Build a list of hierarchical tags for the current path.
		// A response at /blog/2025/02/hello gets tags for:
		//   _path:/blog/, _path:/blog/2025/, _path:/blog/2025/02/, _path:/blog/2025/02/hello
		const segments = path.split("/").filter(Boolean);
		const tags = segments.map(
			(_, i) => `_path:/${segments.slice(0, i + 1).join("/")}/`,
		);

		const body = `<!doctype html><title>${path}</title>`;

		return new Response(body, {
			headers: {
				"Content-Type": "text/html",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": tags.join(","),
			},
		});
	},
} satisfies ExportedHandler;
```

Purging the tag `_path:/blog/2025/` then deletes every cached response whose URL starts with `/blog/2025/`.

For limits on the number, length, and character set of tags, refer to [Cache tag limits](https://developers.cloudflare.com/cache/how-to/purge-cache/purge-by-tags/#a-few-things-to-remember).

### Version-specific purging

By default, Workers Caching [partitions the cache by Worker version](https://developers.cloudflare.com/workers/cache/cache-keys/#invalidating-cache-across-deployments), so each deployment already starts from a cold cache and version-specific purging is unnecessary. This section applies only when you have enabled [`cache.cross_version_cache`](https://developers.cloudflare.com/workers/cache/configuration/#cross-version-caching) to share cached responses across versions. In that case, a response written by version A may still be served after version B is deployed, and you may want to purge the entries a specific version wrote — for example, after a rollback. To do that, tag each response with the version that produced it and purge that tag later.

Add the [version metadata binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/version-metadata/) to your Wrangler configuration:

```jsonc
{
	"name": "my-worker",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-10-05",
	"cache": { "enabled": true, "cross_version_cache": true },
	"version_metadata": { "binding": "CF_VERSION_METADATA" },
}
```

```toml
name = "my-worker"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-10-05"

[cache]
enabled = true
cross_version_cache = true

[version_metadata]
binding = "CF_VERSION_METADATA"
```

Then prepend the version ID to your tags:

*src/index.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		const { id: versionId } = env.CF_VERSION_METADATA;
		const postId = new URL(request.url).pathname.split("/").pop() ?? "unknown";

		return new Response(JSON.stringify({ id: postId }), {
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "public, max-age=3600",
				// Include the version ID as a tag so you can purge by version later.
				"Cache-Tag": `post,post-${postId},v:${versionId}`,
			},
		});
	},
};
```

*src/index.tsts*

```ts
interface Env {
	CF_VERSION_METADATA: WorkerVersionMetadata;
}

export default {
	async fetch(request, env, ctx): Promise<Response> {
		const { id: versionId } = env.CF_VERSION_METADATA;
		const postId = new URL(request.url).pathname.split("/").pop() ?? "unknown";

		return new Response(JSON.stringify({ id: postId }), {
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "public, max-age=3600",
				// Include the version ID as a tag so you can purge by version later.
				"Cache-Tag": `post,post-${postId},v:${versionId}`,
			},
		});
	},
} satisfies ExportedHandler<Env>;
```

When you want to purge everything a specific version wrote — for example, after a rollback — purge the version tag:

*src/admin.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		const versionId = new URL(request.url).searchParams.get("version");
		if (!versionId) return new Response("Missing version", { status: 400 });

		await ctx.cache.purge({ tags: [`v:${versionId}`] });

		return new Response("Purged", { status: 200 });
	},
};
```

*src/admin.tsts*

```ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		const versionId = new URL(request.url).searchParams.get("version");
		if (!versionId) return new Response("Missing version", { status: 400 });

		await ctx.cache.purge({ tags: [`v:${versionId}`] });

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;
```

## Purge by path prefix

`pathPrefixes` purges every cached response whose **request path** begins with one of the given prefixes:

*src/index.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		// Purge everything under /blog/2025/ for the current entrypoint.
		await ctx.cache.purge({
			pathPrefixes: ["/blog/2025/"],
		});

		return new Response("Purged", { status: 200 });
	},
};
```

*src/index.tsts*

```ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Purge everything under /blog/2025/ for the current entrypoint.
		await ctx.cache.purge({
			pathPrefixes: ["/blog/2025/"],
		});

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;
```

Entries in `pathPrefixes` are **paths**, not full URLs. A prefix must not include a scheme, host, query string, or fragment — passing something like `https://example.com/blog/` is invalid input, not a prefix that simply fails to match. A leading slash is optional (`/images` and `images` are treated the same) but recommended for clarity.

`pathPrefixes` is scoped to the entrypoint that makes the purge call. A `purge({ pathPrefixes: ["/blog/"] })` from `PublicAPI` will not affect cached responses stored by `AdminAPI`, even when their paths also start with `/blog/`.

### Purge a single URL

There is no dedicated "purge by URL" mode. To purge a single cached URL, pass its path as a single-element `pathPrefixes` array:

*src/index.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		// Purge the cached response for exactly /blog/2026/hello-world.
		await ctx.cache.purge({
			pathPrefixes: ["/blog/2026/hello-world"],
		});

		return new Response("Purged", { status: 200 });
	},
};
```

*src/index.tsts*

```ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Purge the cached response for exactly /blog/2026/hello-world.
		await ctx.cache.purge({
			pathPrefixes: ["/blog/2026/hello-world"],
		});

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;
```

Because `pathPrefixes` matches on the start of the request path, passing the full path matches only that path — plus any paths that happen to extend it (for example, `/blog/2026/hello-world-2`). If you need exact-match semantics with no risk of over-purge, use a [tag](#purge-by-tag) instead.

## Purge everything

Delete every cached response stored by the calling entrypoint:

*src/index.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		await ctx.cache.purge({ purgeEverything: true });

		return new Response("Purged", { status: 200 });
	},
};
```

*src/index.tsts*

```ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		await ctx.cache.purge({ purgeEverything: true });

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;
```

Use this sparingly. Purging everything causes all subsequent requests to miss the cache until they can be re-filled, which temporarily increases load on your Worker and any upstream services it calls.

## Invalidate cached responses

`invalidate()` is the soft counterpart of `purge()`. It accepts the same options (`tags`, `pathPrefixes`, or `purgeEverything`), selects cached responses the same way, follows the same [per-entrypoint scoping](#purge-modes), and resolves to the same [result object](#return-value). You can call it as `ctx.cache.invalidate(...)` or as `cache.invalidate(...)` imported from `cloudflare:workers` — the [same two forms](#two-ways-to-call-purge) as `purge()`.

The two methods differ in what happens to the matching cached responses:

| Method | Matching cached responses | Next matching request |
| --- | --- | --- |
| `purge()` | Deleted | Cache miss. Your Worker runs and produces a fresh response. |
| `invalidate()` | Kept, but marked stale | Revalidated. The cache sends your Worker a conditional request instead. |

To revalidate an invalidated response, the cache calls your Worker with conditional request headers built from the validators stored with the response — for example, `If-None-Match` carrying the cached `ETag`, or `If-Modified-Since` carrying the cached `Last-Modified`. If your Worker answers `304 Not Modified`, the cache keeps the stored body and serves it with `Cf-Cache-Status: REVALIDATED`, and later requests are `HIT`s again. If your Worker answers with a full `200` response instead, that response replaces the cached one.

`invalidate()` therefore saves work only when your Worker emits validators (`ETag` or `Last-Modified`) and answers matching conditional requests with `304`. This helps most when one call covers many responses but only some of them changed. Each unchanged response then costs a validator check instead of a full regeneration. If your Worker does not emit validators, or always answers with a full response, every revalidation regenerates the response and `invalidate()` saves no work compared to `purge()`.

In this example, a catalog sync writes every product and then invalidates all product pages. Each product carries a revision that changes only when its data changes, and the Worker uses that revision as the `ETag`. Pages for unchanged products revalidate with `304`, so the Worker renders only the pages that changed:

*src/index.jsjs*

```js
function renderProductPage(product) {
	// Stands in for the expensive rendering work that a 304 response skips.
	return `<!doctype html><title>${product.name}</title>`;
}

export default {
	async fetch(request, env, ctx) {
		const url = new URL(request.url);

		if (request.method === "POST" && url.pathname === "/sync") {
			// Write every product from the upstream catalog. Many are unchanged.
			const products = await request.json();
			await Promise.all(
				products.map((product) =>
					env.PRODUCTS.put(product.id, JSON.stringify(product)),
				),
			);

			// Mark every cached product page stale instead of deleting it.
			await ctx.cache.invalidate({ tags: ["products"] });

			return new Response("Synced", { status: 200 });
		}

		const id = url.pathname.split("/").pop() ?? "";
		const product = await env.PRODUCTS.get(id, "json");
		if (!product) return new Response("Not found", { status: 404 });

		const etag = `"${product.revision}"`;
		const headers = {
			"Cache-Control": "public, max-age=86400",
			"Cache-Tag": `products,product-${id}`,
			ETag: etag,
		};

		// To revalidate an invalidated response, the cache sends the stored ETag
		// in If-None-Match. If the product has not changed, answer 304 and skip
		// rendering. The cache keeps the body it already has.
		if (request.headers.get("If-None-Match") === etag) {
			return new Response(null, { status: 304, headers });
		}

		return new Response(renderProductPage(product), {
			headers: { ...headers, "Content-Type": "text/html" },
		});
	},
};
```

*src/index.tsts*

```ts
interface Env {
	PRODUCTS: KVNamespace;
}

interface Product {
	id: string;
	name: string;
	// Changes only when the product data changes.
	revision: string;
}

function renderProductPage(product: Product): string {
	// Stands in for the expensive rendering work that a 304 response skips.
	return `<!doctype html><title>${product.name}</title>`;
}

export default {
	async fetch(request, env, ctx): Promise<Response> {
		const url = new URL(request.url);

		if (request.method === "POST" && url.pathname === "/sync") {
			// Write every product from the upstream catalog. Many are unchanged.
			const products = await request.json<Product[]>();
			await Promise.all(
				products.map((product) =>
					env.PRODUCTS.put(product.id, JSON.stringify(product)),
				),
			);

			// Mark every cached product page stale instead of deleting it.
			await ctx.cache.invalidate({ tags: ["products"] });

			return new Response("Synced", { status: 200 });
		}

		const id = url.pathname.split("/").pop() ?? "";
		const product = await env.PRODUCTS.get<Product>(id, "json");
		if (!product) return new Response("Not found", { status: 404 });

		const etag = `"${product.revision}"`;
		const headers = {
			"Cache-Control": "public, max-age=86400",
			"Cache-Tag": `products,product-${id}`,
			ETag: etag,
		};

		// To revalidate an invalidated response, the cache sends the stored ETag
		// in If-None-Match. If the product has not changed, answer 304 and skip
		// rendering. The cache keeps the body it already has.
		if (request.headers.get("If-None-Match") === etag) {
			return new Response(null, { status: 304, headers });
		}

		return new Response(renderProductPage(product), {
			headers: { ...headers, "Content-Type": "text/html" },
		});
	},
} satisfies ExportedHandler<Env>;
```

## Purge propagation

Purges triggered by `ctx.cache.purge()` use Cloudflare's [Instant Purge](https://developers.cloudflare.com/cache/how-to/purge-cache/) infrastructure and propagate globally with the same guarantees as zone-level purges.

## Return value

`purge()` and `invalidate()` resolve to the same result object. Check `success` to confirm the request was accepted, and inspect `errors` if it was not:

*src/index.jsjs*

```js
export default {
	async fetch(request, env, ctx) {
		const result = await ctx.cache.purge({ tags: ["blog-posts"] });

		if (!result.success) {
			console.error("Cache purge failed", result.errors);
			return new Response("Purge failed", { status: 500 });
		}

		return new Response("Purged", { status: 200 });
	},
};
```

*src/index.tsts*

```ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		const result = await ctx.cache.purge({ tags: ["blog-posts"] });

		if (!result.success) {
			console.error("Cache purge failed", result.errors);
			return new Response("Purge failed", { status: 500 });
		}

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;
```

On failure, each error in `errors` carries a numeric `code` and a human-readable `message` you can log or surface to the caller.

## Rate limits

`purge()` uses the same rate-limiting system as Cloudflare's zone purge API. However, because Workers Caching is associated with the Worker rather than the zone, Workers Cache always uses the **Free tier limits** described in [Availability and limits](https://developers.cloudflare.com/cache/how-to/purge-cache/#availability-and-limits), regardless of your account or zone plan. When the purge is rate-limited, `success` is `false` and `errors` contains an entry describing the rejection.

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/workers/cache/purge/#page","headline":"Purge and invalidate the cache","description":"Delete cached responses with ctx.cache.purge() or mark them stale with ctx.cache.invalidate() — by tag, by path prefix, or everything.","url":"https://developers.cloudflare.com/workers/cache/purge/","inLanguage":"en","image":"https://developers.cloudflare.com/workers/cache/purge/og.png?v=232653489c14e903","dateModified":"2026-10-03","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/"}}
```
