Static Sites
Publish pre-built HTML, CSS, JavaScript, and assets without a long-running application server.
Static Sites#
A Static Site serves a generated directory of files. Choose it for plain HTML and for frameworks configured to produce a static export. Because no server process runs after the build, a Static Site does not use a start command or runtime health check — it simply uploads the files the build produced and serves them.
This simplicity is the feature: no ports, no health paths to keep alive, and no long-running process to supervise. When your app genuinely needs runtime execution (server rendering, API routes, middleware), a Frontend App is the right alternative.
When to use — and when not to#
Use Static Site when:
- The deliverable is HTML/CSS/JS plus assets: plain HTML, a Vite/React build, an Astro static build, a Next.js app configured with
output: "export", or a SvelteKit app with a static adapter. - Every page can be generated at build time and does not require a Node server at request time.
- You want the smallest, most predictable deployment — build once, serve files.
Do not use Static Site when:
- A route needs server rendering, an API route, middleware that inspects requests, or
next/imageoptimization — choose Frontend App. - The backend is an API server that listens on
PORT— choose Web Service.
Common output directories#
The publish directory is what the platform actually uploads after the build finishes. It must contain the final index.html and any referenced assets. A frequent error is publishing the source directory rather than the output directory.
| Project | Typical build command | Publish directory | What is published |
|---|---|---|---|
| Vite or React | npm run build | dist | Bundled HTML, JS, CSS, and assets. |
| Astro | npm run build | dist | Static output generated by the Astro build. |
| Next.js static export | npm run build | out | Output produced only when output: "export" is set; contains static HTML per route. |
| SvelteKit with a static adapter | npm run build | build | Files produced by the static adapter. |
| Plain HTML | none | . | Hand-written index.html and assets already in the repository. |
The directory must contain the final index.html and referenced assets. Review the detected framework and publish directory in the service configuration before deployment — stale assumptions from a different project can quietly point at the wrong folder.
Build locally before you deploy. Running the same npm run build on your machine and checking that dist (or out, or build) actually contains index.html catches mismatched publish-directory errors before you wait on a remote build.
Next.js static export#
Set output: "export" in the project’s Next configuration, build the project, and publish out. This produces a folder of static HTML — one file per route — with no Next.js server.
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = { output: "export" };
export default nextConfig;Then build and publish:
npm run build # produces ./out when output: "export" is set
# publish directory in NexHost: outDo not upload a normal .next directory to a Static Site; it needs a running server (next start) and should be deployed as a Frontend App. Uploading .next as static files produces an unroutable directory and misleading "index.html not found" errors.
For a mixed project that has both static pages and server-rendered ones, ship two services: the static marketing site as a Static Site and the server-rendered application as a Frontend App or Web Service, each with its own hostname.
Environment variables and build-time inlining#
Static sites bake configuration into the build artifact. A public analytics ID or API origin that your framework reads at build time (for example VITE_API_URL or NEXT_PUBLIC_API_URL) is inlined into the HTML/JS during npm run build. Changing it requires a new deployment so a fresh build can inline the new value.
Never put secrets in client-inlined variables — any NEXT_PUBLIC_ or VITE_ value ends up in the bundle that the browser downloads. Keep credentials in server-side runtime scopes on a service that actually runs a server.
Deploy#
- Select Static Site in New Project.
- Choose a repository, archive, or folder source. Confirm branch and root directory when offered.
- Set the build command (often
npm run buildornpm install && npm run buildfor a plain project) and the publish directory (dist,out,build, or.). - Add any environment variables with the correct scope — typically Build for public static configuration.
- Deploy. Use the deployment detail page to check whether the configured output directory was found and contained
index.html.
On success, the platform serves the published directory at the generated public hostname. You can then attach a custom hostname via Custom Domains.
Troubleshooting#
| Symptom | Likely cause | Fix |
|---|---|---|
| "Publish directory not found" or directory is empty | The path points at source or a non-existent folder | Confirm the output directory from your local npm run build and correct it in the service settings. |
index.html missing, assets missing | Wrong directory or framework preset | Compare the directory listing (ls dist / ls out) against the service configuration; update the publish directory. |
Page shows but API/middleware routes return 404 | The app needs server rendering, not static files | Redeploy as a Frontend App from the source — do not ship .next as static. |
| Updated environment variable not reflected | Static value baked at build time; no new artifact was produced | Start a new deployment so a fresh build can inline the updated value. |
Related documentation#
- Frontend Apps — when the app needs a running Node server.
- Getting Started — choosing the right service before you configure source.
- Static Sites Quickstart — Vite/Astro/Next export specifics.
- Deployment Troubleshooting — fast diagnosis of publish vs build failures.