Skip to content
SubnomicDOCS

Docs · Sites

Updated

Deploy 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.

ToolBuild commandOutput folder
Vite (React, Vue, Svelte, plain)npm run builddist
Astro (static output)npm run builddist
Hugohugopublic
Eleventynpx @11ty/eleventy_site
Jekyllbundle exec jekyll build_site
Next.js with output: 'export'next buildout
Nuxt, staticnuxt generate.output/public
SvelteKit with adapter-staticnpm run buildbuild
Docusaurusnpm run buildbuild
MkDocsmkdocs buildsite
Plain HTMLnonethe 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:

  1. The output saved in subnomic.json.
  2. Otherwise, the first of dist, build, out, .output/public, public, _site, site and www that is a real directory with an index.html in it. Symlinks are not followed.
  3. 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.

Vite and Astro projects also have a 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 saysWhat 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 publishThe folder is empty, usually because the build has not run in this checkout yet.
there is no earlier deployment to roll back toThe live deployment is the only finished one.
Deep links return 404 after a deployA 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 hostAn 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.