Traffic hits nginx first. Node/Express is not on the raw internet path in the sense that:
- Unknown URLs stop at nginx (
public/file or 404); they never reach Express. - Only explicit
locations forward to the app (documents,/_next/image, health/debug, etc.). - Heavy caching (especially
/_next/static/from disk, documentproxy_cachefor allow‑listed HTML/RSC paths) reduces origin load and absorbs a lot of read traffic before it touches Node.
That’s a deliberate defense‑in‑depth / blast‑radius posture, not “Next out of the box.”
- Normal App Router behavior for routes you explicitly expose: SSR, RSC Flight (
GET /?_rsc=…),/_next/image, etc. can all work as long as nginx forwards them. - Next’s own caching (including Cache Components /
'use cache') still runs when a request reaches Node. The edge is an additional cache layer, not a replacement for Next. - Operational clarity: if Express logs are quiet for a URL class, nginx handled it (static, 404, or full document HIT).
These are platform constraints you accept in exchange for the nginx gate. They’re mostly routing and cache‑semantics, not “Next is broken.”
Next can add routes freely in code; nginx does not know until you update config (and redeploy/reload). Anything not matched by an allow‑listed proxy path is invisible to Node from the internet.
Implication for SRE/BE: new pages, APIs, webhooks, OAuth callbacks, etc. need a checklist item: add/adjust nginx location + cache allowlist maps if applicable.
You block generic /_next/* and only pass known internals (e.g. /_next/image). That’s good for security, but:
Implication: a Next upgrade that introduces a new required internal path would show up as edge404s until nginx is updated. Treat major Next bumps as a small nginx compatibility review.
- Default documents (
/,/images, …): nginx may ignore upstreamCache-Controland use fixed edge TTL behavior. - Paths that honor upstream CC (e.g.
/cache-demo): edge freshness can follow Next’ss-maxage/ revalidation so you don’t “freeze” stale HTML for minutes.
Implication: invalidation is not one button. Deploys namespace keys via build id; time‑based freshness depends on which nginx profile that path uses and what Next emits. SREs should know per‑route edge semantics, not assume one global rule.
Your edge document key includes things like build id, host, path, locale cookie. Anything that changes HTML meaningfully but is not in the key risks wrong shared cache entries.
Implication: if a page varies on auth, feature flags, A/B, tenant, cookie‑gated experiments, etc., you must either:
- Include those dimensions in the nginx cache key, or
- Bypass document cache for those routes, or
- Accept incorrect sharing.
This is the main “footgun” class for BE teams adding personalization.
Flight requests (e.g. GET /?_rsc=…) hit the same path‑based nginx rules as a normal document for that route. That’s fine, but it means:
Implication: client prefetch and soft navigation generate more origin‑shaped traffic than “one HTML per user click.” It’s usually small and highly cacheable, but monitor / (and other layouts) — not only leaf URLs.
Your design is oriented around GET/HEAD document caching and explicit raw proxy blocks. POST/PUT, streaming, SSE, WebSockets (if you add them) need dedicated locations and must not be blindly document‑cached.
Implication: API routes and mutation endpoints belong in the “explicit allow, no document cache” bucket with clear body size / timeout settings on nginx.
Some requests never reach Express → no Node access log for them. Debugging is nginx access logs + response headers (your edge_cache format) plus app logs when the request actually proxies.
Implication: on‑call runbooks should say “check nginx first” for 404s and mystery latency.
- You trade Next’s default “everything on one origin path just works” for explicit edge policy: allowlist, caching, and hiding Node from broad internet reach.
- The limitations are mostly operational and cache‑correctness, not missing Next features: anything you route and cache correctly behaves like Next; anything you forget to route fails closed at nginx (by design).
“We terminate the public internet on nginx with deny‑by‑default routing and aggressive caching; Next/Express only sees explicitly allow‑listed HTTP. That gives strong safety and scale, but every new surface area must be wired in nginx, and we must treat cache keys and dual cache layers as a first‑class design concern.”