diff --git a/src/content/docs/en/guides/caching.mdx b/src/content/docs/en/guides/caching.mdx index 93bdb169a0c75..32174d6abfc09 100644 --- a/src/content/docs/en/guides/caching.mdx +++ b/src/content/docs/en/guides/caching.mdx @@ -32,6 +32,92 @@ export default defineConfig({ You can then use [`Astro.cache`](/en/reference/api-reference/#cache) in your `.astro` pages (or `context.cache` for API routes and middleware) to control caching per request. Cache defaults for groups of routes can also be defined declaratively in your config using [`routeRules`](#route-rules). +If you deploy to Netlify, Vercel, or Cloudflare, you can use their respective adapters' experimental [CDN cache provider](#adapter-cache-providers) instead of the in-memory provider. + +## Adapter cache providers + +Astro's first-party adapters for Netlify, Vercel, and Cloudflare each provide an experimental CDN cache provider that maps cache directives to the platform's native cache headers and invalidation API. Rather than storing responses in memory, these push your caching directives to the host's edge network, and cache hits are served straight from the CDN without invoking your server function. + +During the experimental phase these providers need to be manually enabled, as shown below. In a future release, the Netlify and Vercel providers will be enabled automatically by their adapters. The Cloudflare provider requires a feature that is currently in private beta. + +Each provider automatically tags cached responses with the request path, so [`cache.invalidate({ path })`](/en/reference/api-reference/#cacheinvalidate) works on platforms that only support tag-based purges. + +### Netlify + +

+ + +

+ +Import `cacheNetlify()` from `@astrojs/netlify/cache` and set it as your cache provider: + +```js title="astro.config.mjs" ins={3, 7-9} +import { defineConfig } from 'astro/config'; +import netlify from '@astrojs/netlify'; +import { cacheNetlify } from '@astrojs/netlify/cache'; + +export default defineConfig({ + adapter: netlify(), + cache: { + provider: cacheNetlify(), + }, +}); +``` + +The provider sets `Netlify-CDN-Cache-Control` and `Netlify-Cache-Tag` headers. Cached responses use Netlify's [durable cache](https://docs.netlify.com/platform/caching/#durable-directive) so they are shared across all edge nodes, reducing function invocations. Both tag-based and path-based invalidation are supported. + +### Vercel + +

+ + +

+ +Import `cacheVercel()` from `@astrojs/vercel/cache` and set it as your cache provider: + +```js title="astro.config.mjs" ins={3, 7-9} +import { defineConfig } from 'astro/config'; +import vercel from '@astrojs/vercel'; +import { cacheVercel } from '@astrojs/vercel/cache'; + +export default defineConfig({ + adapter: vercel(), + cache: { + provider: cacheVercel(), + }, +}); +``` + +The provider sets `Vercel-CDN-Cache-Control` and `Vercel-Cache-Tag` headers. Both tag-based and path-based invalidation are supported. Tag invalidation is a soft invalidation: cached responses are marked as stale and revalidated in the background using stale-while-revalidate. + +### Cloudflare + +

+ + +

+ +:::caution[Private beta] +The Cloudflare provider requires the Cloudflare Workers Cache feature, which is currently in private beta. Without beta access the headers are ignored, and calling `cache.invalidate()` will throw an error. +::: + +Import `cacheCloudflare()` from `@astrojs/cloudflare/cache` and set it as your cache provider: + +```js title="astro.config.mjs" ins={3, 7-9} +import { defineConfig } from 'astro/config'; +import cloudflare from '@astrojs/cloudflare'; +import { cacheCloudflare } from '@astrojs/cloudflare/cache'; + +export default defineConfig({ + adapter: cloudflare(), + cache: { + provider: cacheCloudflare(), + }, +}); +``` + +The provider sets `Cloudflare-CDN-Cache-Control` and `Cache-Tag` headers. The adapter enables Worker caching automatically when a Cloudflare cache provider is configured. Both tag-based and path-based invalidation are supported. + ## Interacting with the cache The [`cache` object](/en/reference/api-reference/#cache) provides methods for setting cache options, invalidating entries, and checking the current cache state. This object is available in your `.astro` pages as `Astro.cache`, and in API routes and middleware as `context.cache`. @@ -153,8 +239,8 @@ export default defineConfig({ provider: memoryCache(), }, routeRules: { - '/api/*': { swr: 600 }, - '/products/*': { maxAge: 3600, tags: ['products'] }, + '/api/[...path]': { swr: 600 }, + '/products/[...slug]': { maxAge: 3600, tags: ['products'] }, '/blog/[...slug]': { maxAge: 300, swr: 60 }, }, }); @@ -165,8 +251,7 @@ The following route patterns are supported: - **Static paths**: `/about`, `/api/health` - **Dynamic parameters**: `/products/[id]`, `/blog/[slug]` - **Rest parameters**: `/docs/[...path]` -- **Glob wildcards**: `/api/*` -Patterns use the same matching and priority rules as Astro's [file-based routing](/en/guides/routing/#route-priority-order), so more specific patterns take precedence. +Patterns use the same syntax, matching, and priority rules as Astro's [file-based routing](/en/guides/routing/#route-priority-order), so more specific patterns take precedence. Glob wildcards such as `*` are not supported; use a `[...rest]` parameter to match a group of routes (for example, `/api/[...path]` to match everything under `/api`). Per-route [`cache.set()`](/en/reference/api-reference/#cacheset) calls merge with config-level route rules. Route code can override or extend the defaults set in config. For example, a route rule might set a default `maxAge` for all product pages, but individual pages can call `cache.set()` to customize or disable caching as needed. diff --git a/src/content/docs/en/reference/cache-provider-reference.mdx b/src/content/docs/en/reference/cache-provider-reference.mdx index aac271709ece2..09199d020ebaf 100644 --- a/src/content/docs/en/reference/cache-provider-reference.mdx +++ b/src/content/docs/en/reference/cache-provider-reference.mdx @@ -218,6 +218,67 @@ const factory: CacheProviderFactory = (config) => { export default factory; ``` +When writing a CDN provider, Astro provides [shared utilities](#cache-provider-utilities) for building cache-control headers and path-based invalidation tags. + +## Cache provider utilities + +Astro exports shared helpers for CDN provider authors from `astro/cache/provider-utils`. These are the same helpers used by the first-party Netlify, Vercel, and Cloudflare providers. + +```ts +import { + buildCacheControlDirectives, + pathTag, + setConditionalHeaders, + collectInvalidationTags, + normalizeTags, +} from 'astro/cache/provider-utils'; +``` + +### `buildCacheControlDirectives()` + +

+ +**Type:** (options: CacheOptions, extraDirectives?: string[]) => string | undefined +

+ +Builds a cache-control directive string (e.g. `"public, max-age=300, stale-while-revalidate=60"`) from `CacheOptions`, without a header name so each provider can apply its own (such as `Netlify-CDN-Cache-Control` or `Cloudflare-CDN-Cache-Control`). Pass `extraDirectives` to prepend platform directives such as `public` or `durable`. Returns `undefined` when there are no caching directives. + +### `pathTag()` + +

+ +**Type:** `(path: string) => string` +

+ +Generates a cache tag for a given path (`astro-path:{path}`). Used to support [`invalidate({ path })`](/en/reference/api-reference/#cacheinvalidate) on platforms that only offer tag-based purging. + +### `setConditionalHeaders()` + +

+ +**Type:** (headers: Headers, options: CacheOptions) => void +

+ +Sets `Last-Modified` and `ETag` headers on a `Headers` object from the corresponding `CacheOptions` values. + +### `collectInvalidationTags()` + +

+ +**Type:** (options: InvalidateOptions) => string[] +

+ +Collects all tags needed to invalidate the given options, including the path tag when `options.path` is set. Used by providers that implement path invalidation via tags rather than native path purge. + +### `normalizeTags()` + +

+ +**Type:** `(tags: string | string[] | undefined) => string[]` +

+ +Normalizes a tag value to a flat string array. + ## Cache provider types reference The following types can be imported from the `astro` module: @@ -299,11 +360,13 @@ A unique name for the provider, used in logs and for identification. #### `CacheProvider.setHeaders()`

-**Type:** (options: CacheOptions) => Headers +**Type:** (options: CacheOptions, request: Request) => Headers

Translates cache options into response headers. This is called after the response is rendered but before it is sent to the client. These headers are stripped from the final response. +The incoming `request` is passed as a second argument so a provider can read the URL or request headers. This can be useful to auto-tag responses with their pathname for path-based invalidation. + #### `CacheProvider.onRequest()`