# Frontend Apps

> Deploy a server-rendered Node.js frontend with its own public runtime and automatic listener discovery.

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

---

# Frontend Apps

Choose **Frontend App** for a public UI that must run a Node.js server after the build. It is the correct service for Next.js server rendering, Nuxt server output, Remix, SvelteKit with server adapters, and similar frontend frameworks that cannot be deployed as plain static files.

A Frontend App is not a generic backend with a UI attached — it is a dedicated public runtime whose job is to serve the user interface. Use a [Web Service](/docs/services/web-services) when the service’s primary job is a public API or full-stack backend.

## When to use — and when not to

**Use Frontend App when:**

- Your Next.js project uses server rendering, API routes, server components that fetch data at request time, middleware, `next/image` optimization, or any feature that requires a running server.
- You ship Nuxt with server output, Remix, SvelteKit with `adapter-node`, Astro with SSR, or another Node-based frontend framework that starts a server via `npm run start`.
- You want a separate hostname for the UI distinct from your API’s hostname.

**Do not use Frontend App when:**

- The output is a folder of pre-built HTML/CSS/JS (for example `dist`, `out`, or `build`) that can be served as files with no server — ship it as a [Static Site](/docs/services/static-sites) instead.
- The service is primarily an API or background processor that never renders a UI — use a [Web Service](/docs/services/web-services), [Background Worker](/docs/services/background-workers), or [Private Service](/docs/services/private-services).

> [!INFO]
> If a build can go both ways (many Next.js projects can export statically *or* run as a server), the deciding factor is whether any page, route, or feature needs runtime execution. If even one does, choose Frontend App.

## How it differs from a Static Site

A Static Site publishes generated files such as `dist`, `out`, or `build`; no application server is started. A Frontend App builds your project, then supervises its production start command for the lifetime of the release. The runtime discovers its reachable TCP listener before the release is marked ready.

| Model | What runs after the build | What is checked |
| --- | --- | --- |
| Static Site | The output directory is uploaded and served as files. | No process is started; no runtime readiness is needed. |
| Frontend App | `npm run start` (or equivalent) starts a Node server. | NexHost verifies a reachable TCP listener and assigns ingress automatically. |

If your Next.js project uses `output: "export"`, it produces static files and can be a Static Site. If it uses API routes, server components that need runtime data, middleware, image optimization, or other server features, choose Frontend App. Uploading a normal `.next` directory to a Static Site is not supported — `.next` needs a running server.

## Before you begin

- The project builds locally with `npm run build`.
- The production start script is present and launches a persistent server — for Next.js that is typically `next start`, usually via `npm run start`.
- The application can read `PORT` from the environment and bind to `0.0.0.0`.

## Configure a Node frontend

For a typical Next.js project, the dashboard proposes:

```text
Build command: npm run build
Start command: npm run start
```

Verify each setting rather than accepting blindly:

1. **Build command** — must be the same command you run locally to produce the server build. Use the project’s package manager; do not shell out to a different toolchain in the dashboard unless you have tested it.
2. **Start command** — must keep a process alive. `next start -p $PORT` is common for Next.js; other frameworks use `npm run start` or a small wrapper script. Do not use `npm run build` as the start command; the runtime needs a long-running **server** after the build completes.
3. **Framework stack selection** — review the detected stack. If the dashboard’s suggestion does not match your framework or monorepo layout, adjust the root directory and commands before deploying.
4. **Environment variables** — add runtime values (for example database URLs, API origins) with the appropriate scope. A value the build inlines client-side needs to be present at build time.

Ensure the application’s start script accepts the runtime port. For example, a Next.js script can be written as `next start -p $PORT`, or more explicitly in `package.json`:

```json
{ "scripts": { "build": "next build", "start": "next start -p $PORT" } }
```

NexHost supplies `PORT=3000` as a compatibility default and automatically discovers the listener your application actually opens. A normal internal port such as `3000` is safe because every deployment is isolated in its own Docker network namespace.

> [!WARNING]
> Avoid "build in one command" patterns like `npm run build && npm run start` in the start command. Keep build and start separate: the build phase runs once, then the start command is supervised for the lifetime of the deployment.

## TCP readiness

NexHost does not require a health URL or user-selected port. It waits for the frontend to open a listener on `0.0.0.0`, discovers that port, and creates the public route. If startup readiness times out, inspect the **start command**, **build log**, and server binding first; a successful build followed by a readiness failure is a startup/configuration issue, not a source issue.

## Deploy

1. In **New Project**, choose **Frontend App**.
2. Connect a supported source — a repository, archive, or folder. Confirm the branch and root directory.
3. Review the build and start commands and output expectations.
4. Deploy. On success, the generated public URL and deployment detail page are shown after the release becomes ready.

After the first successful release you can add a custom hostname: [Custom Domains](/docs/configuration/custom-domains) works for every public runtime, including frontend apps.

## Troubleshooting

| Symptom | What to check |
| --- | --- |
| Build succeeds, startup readiness times out | Is the start command a persistent server? Does it bind to `0.0.0.0` and reach its listen call after initialization? |
| `output: "export"` hint in logs, or static-output warnings | A static-style Next build was uploaded. If the app needs server features, choose Frontend App and ship the **source**, not the `.next` or `out` directory. |
| Start script "not found" | Verify the package manager, root directory, and that the workspace has a `package.json` at the chosen path. |

See [Deployment Troubleshooting](/docs/deployments/troubleshooting) for the full symptom table and [Logs](/docs/operations/logs) for how to read each deployment stage.

## Common mistakes

- Reusing `npm run build` where a long-lived start command belongs.
- Uploading the `.next` directory and pointing a Static Site at it — use a Frontend App instead.
- Binding the server only to `127.0.0.1`, which makes it unreachable from the runtime network.

## Related documentation

- [Static Sites](/docs/services/static-sites) — when no server is required.
- [Web Services](/docs/services/web-services) — when the service is primarily an API.
- [Environment Variables](/docs/configuration/environment-variables) — scoping for build-time versus runtime values.
- [Deployment Troubleshooting](/docs/deployments/troubleshooting) — fast diagnosis of build vs startup failures.

