# Static Sites

> Publish pre-built HTML, CSS, JavaScript, and assets without a long-running application server.

Source: https://nexthomelabs.com/docs/services/static-sites
Markdown: https://nexthomelabs.com/docs-md/services/static-sites
Slug: services/static-sites
Section: Create
Last updated: 2026-08-30
Reading time: 5 min read

---

# 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](/docs/services/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/image` optimization — choose [Frontend App](/docs/services/frontend-app).
- The backend is an API server that listens on `PORT` — choose [Web Service](/docs/services/web-services).

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

> [!TIP]
> 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.

```js
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = { output: "export" };
export default nextConfig;
```

Then build and publish:

```bash
npm run build   # produces ./out when output: "export" is set
# publish directory in NexHost: out
```

Do 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](/docs/services/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

1. Select **Static Site** in **New Project**.
2. Choose a repository, archive, or folder source. Confirm branch and root directory when offered.
3. Set the **build command** (often `npm run build` or `npm install && npm run build` for a plain project) and the **publish directory** (`dist`, `out`, `build`, or `.`).
4. Add any environment variables with the correct scope — typically Build for public static configuration.
5. 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](/docs/configuration/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](/docs/services/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](/docs/services/frontend-app) — when the app needs a running Node server.
- [Getting Started](/docs/getting-started) — choosing the right service before you configure source.
- [Static Sites Quickstart](/docs/quickstarts/static-sites) — Vite/Astro/Next export specifics.
- [Deployment Troubleshooting](/docs/deployments/troubleshooting) — fast diagnosis of publish vs build failures.

