Why the web is a static export on distroless
No shell, no Node runtime — the marketing surface is a static bundle on distroless/static.

The marketing surface — apps/web — is a static bundle on distroless/static. No Node runtime, no shell, no server process. The content is static; the server is not part of the product.
The marketing surface — apps/web — is a static bundle on distroless/static. No Node runtime, no shell, no server process. The content is static; the server is not part of the product.
Static export, by choice
Next.js can run as a server (SSR, edge, middleware) or as a static export. apps/web is the static export: every page is pre-rendered HTML, CSS, and JS, served from a static file server with no Node process. The marketing site does not need a server because it does not need per-request computation — the content is the content, and the interactive pieces (the demos) are client-side. A static bundle on distroless/static is the honest deployment for a surface that has no server logic.

Why distroless/static
Distroless/static is the smallest possible base: no shell, no package manager, no init, no anything except the static binary and its files. The attack surface is the static assets and the file server, not an operating system. There is no shell to exploit because there is no shell. For a marketing surface that is static content, that is the correct posture: the smallest image that serves the files, and nothing more. A container image scan returns a clean grade because there is nothing there to flag.
No shell, no Node, no server process. The content is the product; the server is not. Distroless/static is the honest deployment for a surface with no server logic.
What runs and what does not
The marketing surface runs as static assets. What does not run: a Node server, an SSR worker, a middleware edge. The interactive demos on the site are client-side — synthetic-data feature slices with no backend call, because a repository is added only when a slice hits the backend, and the marketing demos do not. The backend calls (the SDK, the Eye-Key API) happen from the developer dashboard (apps/app) and the admin console (apps/admin), not from the marketing site. apps/web is read-mostly and demo-only; it is a static export because it has nothing to compute per request.
- Static export: pages pre-rendered, no Node runtime, no SSR, no middleware.
- Distroless/static base: no shell, no package manager — the smallest image that serves the files.
- Interactive demos are client-side synthetic data — no backend call, no repository, no server.
What this buys
The win is operational, not just security. A static bundle is cheap to serve, cheap to cache, cheap to scale (a CDN in front of it does the work). It cannot crash, because there is no process. It cannot OOM, because there is no runtime. It cannot have a dependency vulnerability in a server framework, because there is no server framework. The marketing surface is the first thing a visitor sees and the last thing that should be down — and a static bundle is the way to make that true. The demos that need data are synthetic; the data that is real lives behind the authenticated apps, not here.
The marketing surface is the first thing a visitor sees and the last thing that should be down. A static bundle cannot crash, because there is no process to crash.
— apps/web deployment note
What it is not
This is not a claim that every app is static. apps/app and apps/admin are not static exports — they have auth, dashboards, and real backend calls, and they ship differently. The static-export posture is specific to the marketing surface, which has no per-request server logic. We are pre-revenue and building the POC; apps/web is a static export on distroless/static, and the forecast and oracle surfaces that need a server are separate apps with separate deployment postures.