Merge pull request #26 from ArnasDon/fix/cache-control-headers

fix(deploy): Cache-Control headers so CDN stops serving stale HTML
This commit is contained in:
Arnas Donauskas 2026-04-17 14:36:39 +03:00 committed by GitHub
commit f8543270d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,7 +1,65 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
/**
* Cache-Control policy.
*
* Why this exists:
* Hostinger's CDN was applying `s-maxage=31536000` (1 year) to
* prerendered HTML pages by default. When a new deploy shipped
* fresh Turbopack chunk hashes, the edge kept serving year-old
* HTML referencing chunk filenames that no longer existed on
* disk — result: HTML 200, every /_next/static/*.js and .css
* came back 404, the page rendered unstyled. Private/incognito
* did nothing because the cache is server-side.
*
* Strategy:
* - /_next/static/* — immutable for a year. Filenames are
* content-hashed, so a new build produces new filenames; the
* old ones are safe to keep indefinitely in caches.
* - /api/* — no-store. API responses are per-user and
* must never be shared across requests at the edge.
* - Everything else — public, brief s-maxage + generous
* stale-while-revalidate. The edge serves instantly from cache
* for the first 5 min, then returns cached content while
* refreshing in the background for up to 24 h. A deploy's
* chunk-hash drift self-heals within ~5 min with no user-
* visible latency.
*
* Note: dynamic dashboard routes (/inbox, /contacts, /pipelines,
* /broadcasts, etc.) are server-rendered per request — Next.js
* and Supabase auth already prevent them from being served
* from a shared cache. The s-maxage here is a ceiling; Next.js
* and auth middleware still set `private` / `no-store` for
* per-user responses.
*/
async headers() {
return [
{
source: "/_next/static/:path*",
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
},
],
},
{
source: "/api/:path*",
headers: [{ key: "Cache-Control", value: "no-store" }],
},
{
source: "/:path*",
headers: [
{
key: "Cache-Control",
value:
"public, max-age=0, s-maxage=300, stale-while-revalidate=86400",
},
],
},
];
},
};
export default nextConfig;