Skip to content

Comments

Add docs for experimental route caching#13305

Open
ascorbic wants to merge 2 commits intov6from
v6-route-caching
Open

Add docs for experimental route caching#13305
ascorbic wants to merge 2 commits intov6from
v6-route-caching

Conversation

@ascorbic
Copy link
Contributor

Description (required)

Adds docs for the experimental route caching flag. See the code PR: withastro/astro#15579 and the RFC: withastro/roadmap#1245 for more details

Also updates the live collections docs to refer to route caching in the sections about cache hints.

Related issues & labels (optional)

  • Closes #
  • Suggested label:

@netlify
Copy link

netlify bot commented Feb 23, 2026

Deploy Preview for astro-docs-2 ready!

Name Link
🔨 Latest commit 9932340
🔍 Latest deploy log https://app.netlify.com/projects/astro-docs-2/deploys/699c7fe14d6d99000807b57f
😎 Deploy Preview https://deploy-preview-13305--astro-docs-2.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@astrobot-houston
Copy link
Contributor

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
en/reference/content-loader-reference.mdx Source changed, localizations will be marked as outdated.
en/reference/experimental-flags/route-caching.mdx Localization added, will be marked as complete.
en/reference/modules/astro-content.mdx Source changed, localizations will be marked as outdated.
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@sarah11918 sarah11918 added add new content Document something that is not in docs. May require testing, confirmation, or affect other pages. 6.0 merge-on-release Don't merge this before the feature is released! (MQ=approved but WAIT for feature release!) labels Feb 23, 2026
@sarah11918 sarah11918 added this to the v6.0.0 docs milestone Feb 23, 2026
Copy link
Member

@sarah11918 sarah11918 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, @ascorbic ! Only a very few small comments from me (most of them just adding specific link anchors that were probably too annoying for you to hunt down in the moment).

I think this one just needs to go straight to @yanthomasdev , for whom I've left all the commas! 🎉


Route caching integrates directly with [live content collections](/en/guides/content-collections/#live-content-collections). `cache.set()` accepts `CacheHint` and `LiveDataEntry` objects natively, allowing cache hints from loaders to be passed through without manually setting headers.

A [live loader](/en/reference/content-loader-reference/) can return a `cacheHint` on individual entries or on the collection as a whole. These hints include `tags` (for targeted invalidation) and `lastModified` (for freshness). When passed to `cache.set()`, they merge with any other cache options already set on the page.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A [live loader](/en/reference/content-loader-reference/) can return a `cacheHint` on individual entries or on the collection as a whole. These hints include `tags` (for targeted invalidation) and `lastModified` (for freshness). When passed to `cache.set()`, they merge with any other cache options already set on the page.
A [live loader](/en/reference/content-loader-reference/#live-loaders) can return a `cacheHint` on individual entries or on the collection as a whole. These hints include `tags` (for targeted invalidation) and `lastModified` (for freshness). When passed to `cache.set()`, they merge with any other cache options already set on the page.

}
```

Tag-based invalidation removes all cached entries whose tags include any of the provided tags. Path-based invalidation is exact-match only (no glob or wildcard patterns).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Tag-based invalidation removes all cached entries whose tags include any of the provided tags. Path-based invalidation is exact-match only (no glob or wildcard patterns).
Tag-based invalidation removes all cached entries whose tags include any of the provided tags. Path-based invalidation is exact-match only (no [glob](/en/guides/imports/#glob-patterns) or wildcard patterns).

Totally optional. Just remembered that we have a section about this, so could link there if we thought it was useful.

- **Rest parameters**: `/docs/[...path]`
- **Glob wildcards**: `/api/*`

Patterns use the same matching and priority rules as Astro's [file-based routing](/en/guides/routing/), so more specific patterns take precedence.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Patterns use the same matching and priority rules as Astro's [file-based routing](/en/guides/routing/), so more specific patterns take precedence.
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.


Enables a platform-agnostic API for caching responses from [on-demand rendered](/en/guides/on-demand-rendering/) pages and endpoints. Cache directives set in your routes are translated into the appropriate headers or runtime behavior depending on your configured cache provider.

Route caching builds on standard [HTTP caching semantics](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching) including `max-age` and [`stale-while-revalidate`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate), with support for tag-based and path-based invalidation, config-level route rules, and pluggable cache providers that adapters can set automatically.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering whether somewhere around here in the intro, it's worth comparing this feature to ISR? (Astro's solution to X, sometimes known as ISR; Astro's answer to what's normally solved with ISR; While other frameworks attempt to do X with ISR, Astro's route caching accomplishes X+...)

Totally not necessary of course, just thinking how we could have an SEO hit for Astro + ISR and also be able to point people somewhere when they say "what about ISR?"


Enables a platform-agnostic API for caching responses from [on-demand rendered](/en/guides/on-demand-rendering/) pages and endpoints. Cache directives set in your routes are translated into the appropriate headers or runtime behavior depending on your configured cache provider.

Route caching builds on standard [HTTP caching semantics](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching) including `max-age` and [`stale-while-revalidate`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate), with support for tag-based and path-based invalidation, config-level route rules, and pluggable cache providers that adapters can set automatically.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Route caching builds on standard [HTTP caching semantics](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching) including `max-age` and [`stale-while-revalidate`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate), with support for tag-based and path-based invalidation, config-level route rules, and pluggable cache providers that adapters can set automatically.
Route caching builds on standard [HTTP caching semantics](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching), including `max-age` and [`stale-while-revalidate`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate), with support for tag-based and path-based invalidation, config-level route rules, and pluggable cache providers that adapters can set automatically.


### Collection-level cache hints

When fetching a full collection with `getLiveCollection()`, Astro merges cache hints from the collection response and all individual entries: tags are accumulated and the most recent `lastModified` wins.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
When fetching a full collection with `getLiveCollection()`, Astro merges cache hints from the collection response and all individual entries: tags are accumulated and the most recent `lastModified` wins.
When fetching a full collection with `getLiveCollection()`, Astro merges cache hints from the collection response and all individual entries: tags are accumulated, and the most recent `lastModified` wins.


### `CacheNotEnabled`

Thrown when `Astro.cache` or `context.cache` is used but `experimental.cache` is not configured. The error message explains how to enable the feature.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Thrown when `Astro.cache` or `context.cache` is used but `experimental.cache` is not configured. The error message explains how to enable the feature.
Thrown when `Astro.cache` or `context.cache` is used, but `experimental.cache` is not configured. The error message explains how to enable the feature.


## Dev mode behavior

In dev mode, the cache API is available so route code does not need conditional checks, but no actual caching occurs. `cache.set()` calls are accepted silently, and `cache.invalidate()` is a no-op.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In dev mode, the cache API is available so route code does not need conditional checks, but no actual caching occurs. `cache.set()` calls are accepted silently, and `cache.invalidate()` is a no-op.
In dev mode, the cache API is available so that route code does not need conditional checks, but no actual caching occurs. `cache.set()` calls are accepted silently, and `cache.invalidate()` is a no-op.

Copy link
Member

@ArmandPhilippot ArmandPhilippot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feature looks great! I left a few suggestions, some are nitpickings and others are for consistency with the rest of the docs (e.g. use of tables which don't look very good on small devices).


To enable this feature, configure `experimental.cache` with a cache provider in your Astro config:

```js title="astro.config.mjs" ins={2} ins="memoryCache"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was confused when scanning the page before reading because the node import is highlighted but not its use so I first thought this was a leftover.

Would it makes sense to use ins (green) for what's new and regular highlighting for node (both the import and its use)?

Suggested change
```js title="astro.config.mjs" ins={2} ins="memoryCache"
```js title="astro.config.mjs" {2,5} ins="memoryCache"


The following example caches a page for 2 minutes, serves stale content for 1 minute while revalidating, and tags the response for targeted invalidation:

```astro title="src/pages/index.astro" ins={3-7}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slight misalignment:

Suggested change
```astro title="src/pages/index.astro" ins={3-7}
```astro title="src/pages/index.astro" ins={4-8}

<h1>{entry.data.name}</h1>
```

A `LiveDataEntry` can also be passed directly. Astro extracts its `cacheHint` automatically:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: for those who don't know that this is the return type for getLiveEntry() maybe a link to the type can help:

Suggested change
A `LiveDataEntry` can also be passed directly. Astro extracts its `cacheHint` automatically:
A [`LiveDataEntry`](/en/reference/content-loader-reference/#livedataentry) can also be passed directly. Astro extracts its `cacheHint` automatically:

**Default:** `{ max: 1000 }`

</p>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the preview, I feel we miss en sentence here to separate the two headings. Maybe something like:

Suggested change
To further control how entries are cached, you can use the following options.


1. **The runtime module** — A file that **default-exports** a `CacheProviderFactory` function. This module is bundled into your SSR output, so it must be runtime-agnostic: avoid Node.js built-in modules (e.g. `node:fs`, `node:path`) unless your target runtime supports them.

2. **The config helper** — A function exported for users to call in `astro.config.mjs`. It returns a `CacheProviderConfig` object (`{ entrypoint, config }`) that tells Astro where to find the runtime module and what options to pass it. This is the same pattern used by `memoryCache()` from `astro/config`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a link to the reference is more helpful than the parentheses?

Suggested change
2. **The config helper** — A function exported for users to call in `astro.config.mjs`. It returns a `CacheProviderConfig` object (`{ entrypoint, config }`) that tells Astro where to find the runtime module and what options to pass it. This is the same pattern used by `memoryCache()` from `astro/config`.
2. **The config helper** — A function exported for users to call in `astro.config.mjs`. It returns a [`CacheProviderConfig` object](#cacheproviderconfig) that tells Astro where to find the runtime module and what options to pass it. This is the same pattern used by `memoryCache()` from `astro/config`.

});
```

The runtime module default-exports a factory that receives the serialized `config` and returns a `CacheProvider`:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a link can be helpful for those who want to learn more about the API:

Suggested change
The runtime module default-exports a factory that receives the serialized `config` and returns a `CacheProvider`:
The runtime module default-exports a factory that receives the serialized `config` and returns a [`CacheProvider`](#cacheprovider-interface):

```

### `CacheProvider` interface

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually have an introductory sentence here. Maybe something like:

Suggested change
Describes a provider used for caching. This requires the `name` and `invalidate()` properties and accepts optional properties.


</p>

Optional. Translates cache options into response headers. Called after the response is rendered but before it is sent to the client. These headers are stripped from the final response.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll note we usually don't start the description with "Optional"/"Required"... but maybe this is something to consider for the API block (alongside "Type", "Default"...).


<p>

**Type:** `Readonly<CacheOptions>`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is described right above but for someone redirected to this section, a link to the full object might be helpful:

Suggested change
**Type:** `Readonly<CacheOptions>`
**Type:** <code>Readonly\<<a href="#cacheoptions>CacheOptions</a>\></code>

Comment on lines +530 to +533
| Property | Type | Description |
| -------- | -------------------- | --------------------------------------------------------------------- |
| `path` | `string` | Exact path to invalidate. No glob or wildcard support. |
| `tags` | `string \| string[]` | Tag or tags to invalidate. All entries with matching tags are purged. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, we usually don't use tables and this is not the most usable on small devices.

| `swr` | `number` | Stale-while-revalidate window in seconds. Stale content is served while a fresh response is generated in the background. |
| `tags` | `string[]` | Cache tags for targeted invalidation. Tags accumulate across multiple `set()` calls. |
| `lastModified` | `Date` | When multiple `set()` calls provide `lastModified`, the most recent date wins. |
| `etag` | `string` | Entity tag for conditional requests. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it seems I forgot to add this comment... 🤦🏽 (with the screenshot my comment about tables/small devices will make more sense I guess)

I'm a bit confused by this. We usually don't use tables in docs because they look a bit awful on small devices. We usually use headings for each. This how it looks using Firefox iPhone 11 preview:

screenshot of the table rendered in Firefox iPhone 11 preview

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.0 add new content Document something that is not in docs. May require testing, confirmation, or affect other pages. merge-on-release Don't merge this before the feature is released! (MQ=approved but WAIT for feature release!)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants