Skip to content

Route caching #1140

@ascorbic

Description

@ascorbic

Astro route caching

Summary

Introduce a platform-agnostic route caching API for Astro SSR pages. This feature enables developers to declaratively define caching rules per route and dynamically override them in middleware or API handlers. It provides a consistent API across Node.js, Vercel, Netlify, Cloudflare, and other deployment targets, ensuring efficient caching while allowing cache invalidation by path or tag when supported. Where possible it will be implemented using CDN caches, but with fallback implemntations where this isn't supported.

Background & Motivation

Currently, caching in Astro SSR requires manually setting Cache-Control or CDN-Cache-Control headers, which vary per platform and is not ergonomic. Many modern frameworks offer built-in support for SSR caching strategies, allowing pages to be served efficiently while reducing function invocations and improving performance.

Astro's current lack of a unified caching API means that users must implement custom caching solutions per deployment target, leading to unnecessary complexity. This proposal introduces a framework-level abstraction for caching that integrates seamlessly with Astro’s adapter system, providing an intuitive DX while using platform-specific caching mechanisms where available.

Goals

  • Provide a platform-agnostic caching API for Astro SSR routes and server islands.
  • Support TTL, stale-while-revalidate (SWR), and ETag-based caching.
  • Cache in the CDN where possible, using HTTP cache or CacheStorage.
  • Allow declarative caching definitions in config, with overrides in Astro pages and server islands.
  • Enable imperative cache invalidation via by path and tag for fine-grained control.
  • Use platform-specific caching mechanisms (CDN, edge cache, etc.) via Astro adapters where available.
  • Maintain a consistent API and DX across deployment targets.

Non-goals

  • Persistent cache storage in core. This is delegated to the CDN.
  • fetch cache. This is for responses only.
  • Page fragment cache, except for server islands. This is designed for caching complete responses.
  • Browser cache handling, except for setting etag and respecting conditional requests.
  • Cache rules for prerendered pages.

Example

Declarative API

Cache rules can be declared via route patterns in config:

// astro.config.mjs
export default {
  cache: {
    routes: {
      '/': { maxAge: 0, swr: 60 },
      '/blog/**': { maxAge: 300 },
      '/api/**': { maxAge: 600 },
    }
  }
};

They can be overridden in an Astro page or island's frontmatter:

---
Astro.cache({
  maxAge: 300,  // Cache for 5 minutes
  swr: 3600,    // Allow stale content for 1 hour while revalidating. In seconds or boolean. Default `true`, meaning 1 hour.
  tags: ['blog', 'blog:1'],   // Optional cache tags for invalidation
});
---

<html>…</html>

Invalidation

Helper functions allow cache invalidation where the adapter supports it:

// In an API handler or webhook:
export const POST: APIRoute = ({ cache }: APIContext) => {
	cache.invalidate({
 	   path: '/blog/my-article', // Invalidate a single page
 	   tag: ['blog', 'home'] // Invalidate all pages tagged as "blog" or "home"
	});  

	return Response.json({
		ok: true,
		user: 1,
	});
};

This uses adapter hooks under the hood, which call the platform-specific APIs. By providing a unified API, Astro ensures that caching is easy to configure while remaining adaptable to different hosting environments.

Adapter support

Each platform has slightly different levels of support, so would need to declare this via adapter features. For example, some platforms don't support cache tags and some don't support invalidation.

Where possible, adapter support would be implemented with CDN-Cache-Control headers. The cache config could allow users to specify the header names, for example.

We would implement an optional lightweight cache for the Node adapter using in-memory LRU, but would recommend using an external proxy or CDN cache.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Stage 2: Accepted Proposals, No RFC

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions