Guides

Deploying static sites

Deploy source with managed static builders or upload built files, and configure redirects, headers, and 404 pages.

A static site works with nothing but HTML, JS, CSS, and image files, no server. The files are served from the edge (servers close to your visitors), so it is fast and needs almost no setup. You can deploy framework source with a managed preset or upload an already-built folder.

Deploy

Install the CLI

curl -fsSL https://nitroship.co/install.sh | bash
ntro login

Already installed? Skip ahead. Full options, PATH setup, and updates: Install the CLI.

Build from source with a managed preset

Deploy the project root, not its output folder. Nitroship installs dependencies, runs the framework build, and publishes the resulting static files.

ntro apps create my-static-site
ntro deploy . --prod
ProjectManaged static build
Vite or Create React AppVite and React SPAs
AngularAngular, configured for static output
Gatsby, Docusaurus, VitePress, EleventyStatic generators, built with the Node toolchain
Hugo, Jekyll, MkDocsStatic generators, built in a generated toolchain container
Frameworks with static modesFollow the static-mode setup for Nuxt, Astro, SvelteKit, or Qwik
Plain HTML or already-built filesStatic HTML

Both static (a Node-toolchain build or plain files) and container-static (a toolchain image that exports only the built site) publish files to the CDN without a compute runtime. A framework that emits a server instead uses a managed Node bundle or container; it is not a static deployment merely because it has client assets.

Detection first honors build.framework in nitroship.json, even when a root Dockerfile exists. It cannot be combined with build.dockerfile. Without an explicit framework, Nitroship checks a configured Dockerfile or root Dockerfile.nitroship/Dockerfile, then the dedicated Next.js adapter, then the managed framework registry, and finally generic static files.

For a generic static build, configure the build command and output directory:

nitroship.json
{
  "build": {
    "framework": "static",
    "command": "npm run build",
    "outputDirectory": "dist"
  }
}

Use the framework slug instead of static when you want its preset to choose the build and output settings. Follow the linked framework guide for its build requirements.

--local supports static and managed Node builds. For container-static generators such as Hugo, Jekyll, and MkDocs, drop --local so the remote builder can run the toolchain image.

Upload already-built files

If you build yourself, deploy the folder that holds your build output.

ntro apps create my-static-site
ntro deploy ./dist --app my-static-site --prod

A subfolder like ./dist has no app link, so add --app. Deployed files never change; deploy again to update them.

Address rules

Put nitroship.json in the folder you deploy (the deployment root) to set address rules. A vercel.json from Vercel is read in the same format. If both exist, only nitroship.json is read and vercel.json is ignored.

SettingWhat it does
cleanUrlsServes /about.html at /about. Addresses ending in .html redirect to the version without it.
trailingSlashAlways add (true) or always remove (false) the / at the end of addresses.
redirectsSends an old address to a new one. 307 (temporary) by default, 308 (permanent) with "permanent": true.
rewritesShows a different file while keeping the address. Applies only when no real file matches.
headersAdds response headers, such as caching rules, for matching paths.
routesLow-level rules written as regular expressions, for when the above is not enough.

Example: clean addresses, a redirect, and a custom 404

nitroship.json
{
  "cleanUrls": true,
  "redirects": [
    {"source": "/old/:slug", "destination": "/docs/:slug", "permanent": true}
  ],
  "headers": [
    {
      "source": "/assets/(.*)",
      "headers": [{"key": "Cache-Control", "value": "public, max-age=31536000, immutable"}]
    }
  ],
  "routes": [
    {"handle": "filesystem"},
    {"src": "^/.*$", "dest": "/404", "status": 404}
  ]
}
  • The file /about.html opens at /about.
  • /old/hello permanently redirects to /docs/hello; :slug carries over whatever was in that position.
  • Files under /assets/ are cached by browsers for a year. Use this only for files whose names include a content hash, so a new version gets a new name.
  • {"handle": "filesystem"} means "if a real file matches at this point, serve it". Rules after it apply only when no file matched, so unknown addresses show 404.html with status 404.

Unknown setting names are treated as typos and the deployment is rejected. After editing the file, deploy once to check that it is accepted.

The repository's examples/hello-static includes index.html, 404.html, clean addresses, response headers, and caching for hashed files.

Files that are not uploaded

So secrets are not uploaded by accident, these are excluded by default: files starting with .env (.env.example is still uploaded), .git, and .npmrc.

Anything else you want to leave out goes in a different file depending on how you deploy.

Default deploy (remote builder)--local direct upload
Ignore file.gitignore, .ntroignore.nitroshipignore
Always excludednode_modules, .next, .ntroThe .nitroship folder
Re-include with ! rulesYes (e.g. !.env.production)No

Symbolic links are not served as static site files.

On this page