Docs · Sites
UpdatedDeploy a Vite, Astro or Hugo site
subnomic sites deploy publishes a folder you have already built. It never runs your build. So deploying any static site generator comes down to two things: building it, and pointing the CLI at the folder the build wrote. This page lists that folder for the common tools, and what to do when a deploy is refused.
The short version
Install the CLI and sign in once (Getting started), then, from your project directory:
npm run build # or hugo, or your build subnomic sites create my-site --dir dist # once: create and link subnomic sites deploy # a preview URL subnomic sites deploy --prod # the live URL
sites create writes subnomic.json with the site id and the output folder, so later deploys need no flags. Only the URL is written to stdout; progress goes to stderr, so URL=$(subnomic sites deploy --prod) works in a script.
Which folder each tool builds
These are each tool’s default output folders. If you changed yours (build.outDir in Vite, outDir in Astro, publishDir in Hugo), use that instead.
| Tool | Build command | Output folder |
|---|---|---|
| Vite (React, Vue, Svelte, plain) | npm run build | dist |
| Astro (static output) | npm run build | dist |
| Hugo | hugo | public |
| Eleventy | npx @11ty/eleventy | _site |
| Jekyll | bundle exec jekyll build | _site |
Next.js with output: 'export' | next build | out |
| Nuxt, static | nuxt generate | .output/public |
SvelteKit with adapter-static | npm run build | build |
| Docusaurus | npm run build | build |
| MkDocs | mkdocs build | site |
| Plain HTML | none | the folder that holds index.html |
A build that produces a server rather than files, such as a Nuxt server build or a compiled Linux binary, is deployed as a service instead. When the build is a server explains what the CLI recognises and what it refuses.
How deploy picks the folder
When you do not pass --dir, the CLI decides in this order:
- The
outputsaved insubnomic.json. - Otherwise, the first of
dist,build,out,.output/public,public,_site,siteandwwwthat is a real directory with anindex.htmlin it. Symlinks are not followed. - Otherwise,
dist.
.output/public is checked before public because Nuxt writes both. --dir always wins, and .git, .env, node_modules, .DS_Store, .svn and .hg are never uploaded.
public/ folder of source assets. Build first: if dist does not exist yet and public/ happens to hold an index.html, detection would pick your source folder. Saving --dir dist once in subnomic.json removes the guess.Vite and other single-page apps
An app that routes in the browser (React Router, Vue Router) has no file behind /settings. Create its site with the single-page-app switch on, and requests for paths without a file extension are answered with index.html and a 200:
npm run build subnomic sites create my-app --dir dist --spa subnomic sites deploy --prod
For a site that already exists, turn on Single-page app in its settings in the console. A missing script or stylesheet still gets a real 404. A /* /index.html 200 line in _redirects, the rule other hosts use for this, is skipped here: rules accept 301, 302, 303, 307, 308, 404 and 410 only. More in Single-page apps and 404s.
Astro
Astro’s default output is static, which is what this page covers: npm run build writes dist, one HTML file per page. Leave the single-page-app switch off and set an error page instead, so a missing page is served with a 404 status:
npm run build subnomic sites create docs-site --dir dist --not-found /404.html subnomic sites deploy --prod
Hugo
Hugo writes to public. It also bakes baseURL into absolute links, so build with the address the site will be served at:
hugo --minify --baseURL https://www.example.com/ subnomic sites create blog --dir public --not-found /404.html subnomic sites deploy --prod
Hugo does not empty public between builds by default, so a page you deleted from the source can still be published. Run hugo --cleanDestinationDir, or delete public before building.
Previews and rollback
Every deploy is kept whole with its own address. subnomic sites deploy without --prod prints that address and changes nothing live. Going back is moving the live pointer, not rebuilding:
subnomic sites rollback # the deployment before the live one subnomic sites rollback --to <id> # a specific deployment
In a terminal, rollback without --to shows a picker; in CI it takes the one before the live deployment. Only deployments that finished are candidates. Ten earlier deployments are kept beyond the live one. The whole pipeline, with a preview for every pull request, is in Deploy from GitHub Actions.
When a deploy is refused
| The CLI says | What it means |
|---|---|
dist has no index.html — is that the build output directory? | The folder exists but holds no index.html. You pointed at the project, not its build, or the build went somewhere else. Pass --dir. |
dist has no files to publish | The folder is empty, usually because the build has not run in this checkout yet. |
there is no earlier deployment to roll back to | The live deployment is the only finished one. |
| Deep links return 404 after a deploy | A single-page app without the single-page-app switch. Turn it on for the site; a _redirects rule will not do it. |
| Pages link to the wrong host | An absolute base URL baked in at build time: baseURL in Hugo, site in Astro. Rebuild with the site’s address. |
The free plan includes one site, and a deployment’s files count toward its 512 MB of storage, checked before anything is uploaded. Every plan’s numbers are under Sites limits.