Add stale-if-error to app shell Cache-Control (#4009)

## 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) <noreply@anthropic.com>
This commit is contained in:
Josh Harris
2026-05-25 21:13:48 +01:00
committed by GitHub
parent 2b45813ce0
commit 2d6342cd22
2 changed files with 2 additions and 2 deletions
+1 -1
View File
@@ -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<string, Promise<string>>();
+1 -1
View File
@@ -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");
});