From 2d6342cd22ec277ecb4b3bdc3f084210b4fd921a Mon Sep 17 00:00:00 2001 From: Josh Harris Date: Mon, 25 May 2026 21:13:48 +0100 Subject: [PATCH] Add stale-if-error to app shell Cache-Control (#4009) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: Adds `stale-if-error=86400` to the `Cache-Control` header set on the rendered app shell (`/`) in [src/server/RenderHtml.ts](src/server/RenderHtml.ts). This lets shared caches (CloudFlare, nginx `proxy_cache`) keep serving the last good `index.html` for up to 24h if origin returns a 5xx, alongside the existing `stale-while-revalidate` window. Pairs with enabling HTML caching for the `/` route on CloudFlare in "respect origin headers" mode — it already honors `s-maxage` (5 min edge TTL) and `stale-while-revalidate`; this just extends the same safety net to origin-error cases. No behavior change for successful responses; browsers still revalidate every load via `max-age=0`. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: jish --------- Co-authored-by: Claude Opus 4.7 (1M context) --- src/server/RenderHtml.ts | 2 +- tests/server/RenderHtml.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/RenderHtml.ts b/src/server/RenderHtml.ts index 85d90c5e4..675e62a36 100644 --- a/src/server/RenderHtml.ts +++ b/src/server/RenderHtml.ts @@ -7,7 +7,7 @@ import { getRuntimeAssetManifest } from "./RuntimeAssetManifest"; import { ServerEnv } from "./ServerEnv"; const APP_SHELL_CACHE_CONTROL = - "public, max-age=0, s-maxage=300, stale-while-revalidate=86400"; + "public, max-age=0, s-maxage=300, stale-while-revalidate=86400, stale-if-error=86400"; const appShellContentCache = new Map>(); diff --git a/tests/server/RenderHtml.test.ts b/tests/server/RenderHtml.test.ts index 022b93365..ebb27c475 100644 --- a/tests/server/RenderHtml.test.ts +++ b/tests/server/RenderHtml.test.ts @@ -60,7 +60,7 @@ describe("RenderHtml", () => { setAppShellCacheHeaders(response); expect(headers.get("Cache-Control")).toBe( - "public, max-age=0, s-maxage=300, stale-while-revalidate=86400", + "public, max-age=0, s-maxage=300, stale-while-revalidate=86400, stale-if-error=86400", ); expect(headers.get("Content-Type")).toBe("text/html"); });