documentation menu

SPA mode & error pages

Serve /index.html for unmatched routes so client-side routers work, and map status codes to your own pages.

read as markdown

Two options cover the common routing cases for static sites.

Single-page apps

Add --spa and any path that doesn’t match a file is served /index.html with a 200 — so client-side routers (React Router, Vue Router, TanStack Router) handle deep links instead of returning a 404.

spa
$ one9x pages release ./dist --site myapp --spa --deploy✓ Live · unknown routes → /index.html

This is the flag that decides whether an app works. Without it, the first visitor who hard-refreshes on /settings or follows a shared deep link gets a 404 — the app is fine, the routing never got a chance to run.

You need it for a client-rendered app (Vite + React Router, Vue Router, Create React App). You don’t need it for a static site generator that writes a real HTML file per route — Astro, Hugo, Eleventy, Next.js output: 'export' — where an unmatched path genuinely is a 404 and should say so. Frameworks has the per-framework answer.

--spa and --index are the same slot and conflict. --index names a different fallback document; --spa is the shorthand for --index /index.html. Pass one or the other.

Custom error pages

Map a status code to a page in your build with --error code:path. The flag repeats, so you can set as many as you need.

error pages
$ one9x pages release ./dist --site mysite --deploy \  --error 404:/404.html \  --error 403:/403.html✓ Live · custom 404, 403

The path is a path within the release — it has to be a file the build actually produced, at the exact path it lives at. --error 404:/404.html with the file at /404/index.html maps to nothing.

Error pages and --spa interact the way you would want: with --spa on, an unmatched route is not an error at all, so the 404 page is only reached when the app itself asks for it.