Frameworks
Which folder your framework builds to, and whether it needs --spa — the whole answer in one table.
read as markdownPages serves static files, so the only two things you need to know about your framework are which folder it builds to and whether that folder is a single-page app. Everything else is the same command.
| Framework | Build | Output | --spa? | Live |
|---|---|---|---|---|
| Vite (React/Vue/Svelte) | npm run build | dist/ | yes, with client-side routing | demo |
| Next.js | npm run build | out/ | no | demo |
| Astro | npm run build | dist/ | no | demo |
| Nuxt | npx nuxt generate | .output/public/ | no | demo |
| SvelteKit | npm run build | build/ | only with an SPA fallback | demo |
| Create React App | npm run build | build/ | yes | demo |
| Hugo | hugo | public/ | no | demo |
| Eleventy | npx @11ty/eleventy | _site/ | no | demo |
Every demo is deployed by the template repository behind it, on every push, using the same GitHub Action you would use. Press Use this template and you have a repo that does the same:
| template-vite | template-nextjs | template-astro | template-nuxt |
| template-sveltekit | template-create-react-app | template-hugo | template-eleventy |
Starting a new site rather than adding a deploy to one? Templates has whole sites — a blog, a docs site, a landing page with a working waitlist and a portfolio — set up the same way.
Built with Lovable, Bolt, v0, ChatGPT or Claude? Start at AI tools instead.
Not listed? If it writes HTML, CSS and JS to a folder, it works — point
one9x pages release at that folder. The rule of thumb for --spa: if the build
produces one index.html and the router runs in the browser, you need it. If
it produces a real HTML file per route, you don’t.
The --spa decision, in one line
--spa serves /index.html with a 200 for any path that doesn’t match a file.
Without it, a client-rendered app 404s the moment someone hard-refreshes a deep
route or follows a shared link — the app is fine, the router never got to run.
With it on a site that has real per-route HTML files, a genuine typo’d URL
returns your homepage with a 200 instead of a 404, which is worse for both
readers and search engines.
Details and error-page mapping are in SPA mode & error pages.
Things that apply to every framework
Dotfiles are skipped. Anything beginning with a dot — .git, .env,
.DS_Store — stays on your machine. .well-known is the single exception,
because assetlinks.json and apple-app-site-association only work at that
exact URL.
This matters for Nuxt, whose output directory is .output/public/ — the dot is
on a parent of what you deploy. You point the release at the inner folder
(one9x pages release ./.output/public --site mysite), so nothing is dropped.
--exclude globs are single-segment. They use Go’s path.Match, so ** is
not supported and a pattern using it matches nothing rather than erroring. Match
on the file name ('*.map') or exclude the directory (admin).
--spa and --index are the same slot. Pass one, not both.
Pages serves paths, not routes. A request for /about is served
/about/index.html — a build that wrote about.html instead will 404 on every
internal link while the homepage works fine. Most generators do the right thing;
Next.js and SvelteKit need a setting (trailingSlash), and both framework
pages say so.
Build in CI, not on the deploying machine, if you can. GitHub Actions gets you a preview URL per pull request and a publish on merge, which is the point at which the framework question stops mattering — the workflow names the folder once and nobody thinks about it again.