Skip to content

feat: route caching#15579

Draft
ascorbic wants to merge 16 commits intomainfrom
feat/route-caching
Draft

feat: route caching#15579
ascorbic wants to merge 16 commits intomainfrom
feat/route-caching

Conversation

@ascorbic
Copy link
Contributor

Changes

Testing

Docs

@changeset-bot
Copy link

changeset-bot bot commented Feb 19, 2026

🦋 Changeset detected

Latest commit: cd5ebdb

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added pkg: integration Related to any renderer integration (scope) pkg: astro Related to the core `astro` package (scope) docs pr labels Feb 19, 2026
…time

Adds the foundational building blocks for the route caching feature (RFC #1245):

- CacheOptions, CacheProvider, CacheProviderFactory, InvalidateOptions types
- Zod config schema (CacheSchema) registered under experimental.cache
- AstroCache class with set() merge semantics, tags accumulation, invalidate(), _applyHeaders()
- NoopAstroCache for dev mode
- Utility functions: normalizeCacheDriverConfig, cacheConfigToManifest, defaultSetHeaders
- Public type exports from astro package
Integrates the cache system into the full request lifecycle:

- Virtual module vite-plugin for cache driver resolution (resolves from project root)
- SSRManifest: cacheDriver and cacheConfig fields
- BasePipeline: getCacheProvider() with lazy resolution
- RenderContext: creates AstroCache/NoopAstroCache per request, exposes on
  Astro.cache and context.cache (API routes, actions, middleware)
- App base: wraps onRequest for runtime providers, strips CDN headers after;
  applies _applyHeaders for CDN-based providers
- Serialized manifest: cache driver import + config serialization
- Throwing getter on Astro global for prerendered routes
Compiles cache.routes patterns using Astro's existing route parsing
infrastructure (getParts, getPattern, routeComparator). Patterns use
the same [param]/[...rest] syntax as file-based routing. Most specific
route wins, computed once at startup via compileCacheRoutes().
72 unit tests covering:
- AstroCache runtime: set() merge semantics, tags, invalidate, _applyHeaders, _isActive
- Utils: defaultSetHeaders, normalizeCacheDriverConfig, cacheConfigToManifest, isCacheHint, isLiveDataEntry
- NoopAstroCache: all methods callable and no-op
- Route matching: exact paths, dynamic params, rest params, priority ordering

6 integration tests with mock CDN provider:
- CDN-Cache-Control and Cache-Tag from context.cache.set()
- cache.set(false) opt-out, tags-only, config-level routes
- .astro page and API route support
Runtime cache provider for @astrojs/node with:
- In-memory LRU cache (custom Map-based, no external deps)
- SWR support via stale-while-revalidate with background revalidation
- Tag-based and path-based invalidation
- X-Astro-Cache response header (HIT/MISS/STALE) for observability
- Auto-set as default when experimental.cache is enabled without a driver
- Exported as @astrojs/node/cache subpath
8 tests covering the full runtime caching lifecycle:
- Default driver auto-configuration
- Cache hit/miss behavior with body verification
- CDN header stripping for runtime providers
- Tag-based and path-based invalidation
- cache.set(false) opt-out
- Uncached route passthrough
Full phased implementation plan for RFC #1245 covering:
- Phases 1-3: Core types, pipeline wiring, route matching (complete)
- Phase 4: Node adapter with in-memory LRU (complete)
- Phase 5: Cloudflare adapter with CacheW
- Phase 6: Vercel & Netlify adapters
- Phase 7: Documentation
Replace _applyHeaders() and _isActive underscore convention with
symbol-keyed methods behind applyCacheHeaders() and isCacheActive()
helper functions. The symbols are not exported from the astro package,
so users can't access them. Framework call sites import the helpers
from the module directly. NoopAstroCache no longer needs the internal
methods — the helpers handle the no-op case via 'in' checks.
Breaking: cache.routes moved to experimental.routeRules

This commit addresses RFC #1245 feedback:

1. Terminology: Rename 'driver' to 'provider' throughout the cache API.
   Providers have a richer interface (headers, middleware, invalidation)
   than the simpler driver pattern used by sessions/unstorage.

2. Configuration: Move cache route config from cache.routes to
   experimental.routeRules with Nitro-style shortcuts:
   - Flat cache options: { maxAge: 600, swr: 60 }
   - Nested form: { cache: { maxAge: 600 } }
   - Prerender control: { prerender: true }

3. API: Add cache.options getter for full cache state access,
   complementing the existing cache.tags getter.

Files renamed:
- cache-driver.ts → cache-provider.ts (both astro + node adapter)
- mock-cache-driver.mjs → mock-cache-provider.mjs (test fixture)

All 109 tests pass (95 unit + 7 core + 7 node adapter).
routeRules is focused on cache configuration only. Prerender control
will be handled separately if/when it's added to the feature.
@codspeed-hq
Copy link

codspeed-hq bot commented Feb 19, 2026

Merging this PR will degrade performance by 23%

❌ 1 regressed benchmark
✅ 8 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation Rendering: streaming [false], .md file 1.1 ms 1.4 ms -23%

Comparing feat/route-caching (cd5ebdb) with main (d789452)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (00e95c4) during the generation of this report, so d789452 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

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

Labels

docs pr pkg: astro Related to the core `astro` package (scope) pkg: integration Related to any renderer integration (scope)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments