Skip to content

Keep a Cloudflare deploy from serving HTML that its own build invalidated - #17675

Open
danielmlr wants to merge 1 commit into
withastro:mainfrom
danielmlr:fix/cloudflare-deploy-aware-validator
Open

Keep a Cloudflare deploy from serving HTML that its own build invalidated#17675
danielmlr wants to merge 1 commit into
withastro:mainfrom
danielmlr:fix/cloudflare-deploy-aware-validator

Conversation

@danielmlr

Copy link
Copy Markdown

Changes

A deploy that changes rendered output without changing content leaves the validator of a cached page untouched: revalidation resolves to 304, and clients keep HTML that references hashed assets from the previous build (/_astro/<hash>.css is gone after the next build). The cause: every validator the Cloudflare provider can send comes from the caller — cache.set(), CacheHint, routeRules — and describes the content, never the build.

With the CF_VERSION_METADATA binding configured, the provider now reads the Worker version id and

  • adds an astro-version:<id> cache tag, which enables version-specific purging, and
  • folds the id into a weak ETag (W/"<id>:<lastModified-ms>") on responses that already send Last-Modified and do not supply their own etag.

Without the binding, every header is exactly what it was before.

Testing

test/cache-provider.test.ts gains four cases against the preview server:

  • the version tag appears on a cacheable response,
  • the weak ETag carries the same id and the lastModified timestamp,
  • an explicitly supplied etag survives untouched, and
  • a cacheable response without a validator still gets none.

Two fixture pages (/lastmod, /explicit-etag) and the version_metadata binding in the fixture's wrangler.jsonc support them. The prerenderEnvironment: 'node' build path has no automated case because it would need a second fixture build per run; a manual fixture build with a prerendered route and the provider enabled passes.

Docs

The adapter README does not cover route caching, so there is no section to update here. The behavior is worth a paragraph in the Cloudflare adapter guide on docs.astro.build, and I am happy to open that PR.

Details

Responses that carry no validator keep none. Minting W/"<id>" for them would be the wider fix, but it hands a validator to pages whose content changes between deploys, and a cache may then answer 304 until the next deploy. The narrow rule only makes an existing validator deploy-sensitive, which cannot regress a route.

The version id is read through a dynamic import('cloudflare:workers') resolved once at module load, for the same reason invalidate() imports lazily (#16335): a static import breaks the prerenderEnvironment: 'node' build.

onRequest() would be the other place to reach the runtime, but a provider that defines it counts as a runtime cache, and CacheHandler then strips Cache-Tag from the response.

This picks up #17038, which targeted the feat/cdn-cache-providers branch and was closed when that branch was deleted. The version tag that it built on never reached main, so this change adds it.

Add the Worker version id from the `CF_VERSION_METADATA` binding as an
`astro-version:` cache tag, and fold it into a weak `ETag` on responses
that already carry `Last-Modified`. Responses without a validator keep
none, so no route gains a validator it did not have before.
@changeset-bot

changeset-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 38213ad

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

This PR includes changesets to release 43 packages
Name Type
@astrojs/cloudflare Patch
@test/astro-cloudflare-node-prerender-mdx Patch
@test/astro-cloudflare Patch
@test/astro-cloudflare-allowed-hosts Patch
@test/astro-cloudflare-astro-dev-platform Patch
@test/astro-cloudflare-astro-env Patch
@test/astro-cloudflare-binding-image-cache Patch
@test/astro-cloudflare-binding-image-service Patch
@test/astro-cloudflare-cache-provider-wait-until Patch
@test/astro-cloudflare-cache-provider Patch
@test/astro-cloudflare-client-address Patch
@test/astro-cloudflare-compile-custom-image-service Patch
@test/astro-cloudflare-compile-image-service Patch
@test/astro-cloudflare-custom-entryfile Patch
@test/astro-cloudflare-custom-image-service Patch
@test/astro-cloudflare-dev-image-endpoint Patch
@test/astro-cloudflare-external-image-service Patch
@test/astro-cloudflare-external-redirects Patch
@test/cloudflare-incremental-images Patch
@test/astro-cloudflare-internal-redirects Patch
@test/astro-cloudflare-no-output Patch
@test/astro-cloudflare-prerender-node-env Patch
@test/astro-cloudflare-prerender-queue-consumers Patch
@test/astro-cloudflare-prerender-styles Patch
@test/astro-cloudflare-prerenderer-errors Patch
@test/astro-cloudflare-prerenderer-render-error Patch
@test/routing-priority-cloudflare Patch
@test/cf-server-entry Patch
@test/astro-cloudflare-server-island-prerender-framework Patch
@test/astro-cloudflare-sessions Patch
@test/astro-cloudflare-sql-import Patch
@test/cf-ssr-deps Patch
@test/astro-cloudflare-static Patch
@test/astro-cloudflare-svelte-rune-deps Patch
@test/astro-cloudflare-top-level-return Patch
@test/cf-user-optimize-deps Patch
@test/astro-cloudflare-vite-plugin Patch
@test/astro-cloudflare-with-base Patch
@test/astro-cloudflare-with-react Patch
@test/astro-cloudflare-with-solid-js Patch
@test/astro-cloudflare-with-svelte Patch
@test/astro-cloudflare-with-vue Patch
@test/astro-cloudflare-wrangler-preview-platform Patch

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 the pkg: integration Related to any renderer integration (scope) label Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: integration Related to any renderer integration (scope)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant