Menu

Guides

View as Markdown

Static export

Use static export when a route can ship as HTML plus immutable modules and stay correct without a runtime request shell. Kovo proves that by replaying synthetic GET Requests through the same handler that serves the app dynamically, then writing HTML, immutable /c/__v/* modules, and static assets. There is no parallel renderer and no hand-authored static variant.

Exportable route shape#

Export is for L0/L1 pages:

  • Platform behavior, links, forms that submit as plain GETs, CSS, and static assets.
  • Pure client islands whose state is local to the document.
  • Parameterized routes only when staticPaths enumerates concrete paths.
  • No requirement for server refetch after the document is published.

The exporter fails or skips loudly, according to policy, when a route has a guard, unproven session dependence, mutation-only interaction, or an unenumerated param path. This page is the source of truth for that static-export constraint; the deployment guide links back here instead of repeating the diagnostic rules.

When to keep a server#

Use a dynamic request shell for:

  • Mutations and no-JS POST-redirect-GET.
  • Guarded or session-dependent routes and queries.
  • Typed /_q/ reads, refetch-on-focus, async option/search reads, or live subscriptions.
  • Raw endpoint() / webhook() ingress.
  • Parameterized routes whose path set is not known at build time.

An exported document is the artifact. It should not depend on a future server refetch for correctness.

Deploying exported output#

Static output still contains versioned client modules. Upload new /c/__v/* files additively and retain prior versions for at least 24 hours, the same deploy-skew floor dynamic apps obey. If a platform deletes old module files on every deploy, change that behavior before shipping.

Because there is no runtime typed-read surface for exported pages, prefer static export for pages whose client truth is document-local. A page that needs prior-token /_q/ recovery after deploy is a server page, not a pure static page.

Run the exporter#

Use the CLI when you want a checked output directory from an app entry:

sh
kovo export ./src/app.ts --out dist/static --origin https://example.com

If you own the build script, call exportStaticApp directly:

ts
import '@kovojs/server/runtime-bootstrap';
import { exportStaticApp, type StaticExportOptions } from '@kovojs/server/static-export';
import app from './app.js';

const options: StaticExportOptions = {
  outDir: new URL('../dist/static/', import.meta.url),
  origin: 'https://example.com',
  onNonExportable: 'error',
};

await exportStaticApp(app, options);

Set onNonExportable: 'skip' only when the deploy intentionally mixes exported pages with server routes. The skipped paths are still review evidence; do not hide them in a generic site script.

Run it#

Export one app, then inspect the output tree and the exporter report:

sh
kovo export ./src/app.tsx --out dist/static --origin https://example.com
ls -R dist/static

You should see HTML files, static assets, and immutable /c/__v/ modules only for the routes the exporter proved safe to replay.

Checks to run#

For an app project, run the exporter itself in CI:

sh
kovo export ./src/app.tsx --origin https://example.com

That command is the exportability gate. It exits non-zero when a route cannot be replayed faithfully or when earlier app diagnostics already block the build. Add your own link checker only after the export succeeds. Any third-party HTML link checker is fine; Kovo does not ship one for app projects.

Handle failure#

The main export failure is the one you should surface verbatim in CI:

ERROR KV229 Route "/account" is not exportable because it depends on request-time auth or session state.

If the build intentionally mixes exported pages with server routes, rerun with --skip-non-exportable and review the skipped-path report as part of the deploy.

Next#

Spec & diagnostics

Static export through the request shell, L0/L1 limits, guarded/session-dependent route constraints, param path enumeration, and KV229: SPEC §9.5. Prior immutable module retention and KV417: SPEC §14. The MPA degradation contract: SPEC §8.

API reference: @kovojs/server.