# Environment Variables

> Configure build-time and runtime values for a NexHost service without committing them to source.

Source: https://nexthomelabs.com/docs/configuration/environment-variables
Markdown: https://nexthomelabs.com/docs-md/configuration/environment-variables
Slug: configuration/environment-variables
Section: Configure
Last updated: 2026-08-30
Reading time: 6 min read

---

# Environment Variables

Environment variables are how a NexHost service receives values that should not live in source control — database connection strings, third-party API credentials, feature flags, and public client configuration. You set them on the service configuration screen in the dashboard; the platform makes them available at the right moment in the deployment lifecycle.

Keeping configuration out of the repository keeps your history clean and your secrets auditable: a variable can be rotated or removed without rewriting commits.

## When to use this

Use environment variables whenever a value differs between environments, is secret, or would otherwise require editing source between local development and production. Typical examples:

- `DATABASE_URL` or a Postgres connection string that points at the managed database for the workspace.
- API keys for payment, email, or storage providers.
- A `NODE_ENV` or framework feature flag you want to flip without a code change.
- The platform-injected `PORT` that every public Node runtime must read.

Do not use environment variables as a substitute for a proper build artifact: changing a build-time value on a static site still requires a redeployment so a new artifact can be produced.

## Scopes

Each variable can be available during one or both parts of a deployment. Setting the wrong scope is a common source of "works locally, fails in deployment" behavior, so pick deliberately.

| Scope | Use it when | What happens if you change it |
| --- | --- | --- |
| **Build** | A build tool needs the value while generating the application output — for example, a static site that inlines a public API URL at build time. | The value is baked into the produced artifact. Change it and deploy again so a new build can run. |
| **Runtime** | The running process needs the value after it starts — for example, a database password read at startup or an API key used per-request. | The running process receives the value at start. Redeploy or restart the service after changing values that affect startup. |
| **Both** | The value is required during the build and by the running service — for example, a Next.js app that compiles with `NEXT_PUBLIC_` values and also reads a server flag at runtime. | Both of the above apply. Treat the change as a full redeployment trigger. |

Static-site values are incorporated into the built output. Change a build-time value and deploy again so a new artifact is produced. Runtime services receive their runtime configuration when they start; redeploy or restart the service after changing values that affect startup.

> [!INFO]
> A variable scoped to **Build** only will not be present at runtime, and a variable scoped to **Runtime** only will not be present while the build runs. If a build needs to read a value, scope it to Build or Both; if the running server needs to read it, scope it to Runtime or Both.

## Set a value

1. Open the **service settings** in the dashboard.
2. Add the **key**, **value**, and appropriate **scope** (Build, Runtime, or Both).
3. Save the configuration. The dashboard confirms which services are affected.
4. Start a deployment when the change needs a new build or runtime process — most changes do. Do not assume a save alone re-provisions a running container.

**Good habits:**

- Use descriptive keys and group related values (`DATABASE_URL`, `REDIS_URL`, `STRIPE_SECRET_KEY`) so future readers can tell secrets from feature flags.
- Prefer one change per deployment when you are debugging. Updating one variable at a time makes the build log diff small and useful.
- Keep a short local `.env.example` (committed) alongside a real `.env` (ignored) so teammates know which keys exist without sharing values in Git.

## Keep secrets server-side

Do not use browser-exposed variables for credentials. Frontend frameworks may embed specially prefixed values into client-side bundles — for example, Next.js inlines `NEXT_PUBLIC_*` at build time and Vite inlines `VITE_*`. Any value with such a prefix will be visible to anyone who can load the page, regardless of server security.

Rules of thumb:

- If the value is a password, token, private key, or connection string, it must **never** carry a client-side prefix. Scope it to Runtime (or Both only when the server build needs it) and read it only from server code.
- If the value is intentionally public (an analytics ID, a public API origin, a feature label shown in the UI), make that intent explicit in the key name and scope it appropriately — typically Build or Both so the client build can inline it.
- Check your framework’s documentation before putting any sensitive value in a build-time variable. The dashboard cannot undo a client-bundle leak.

> [!WARNING]
> Do not paste real secrets into logs, support tickets, screenshots, or chat messages. When you need to share diagnostic output, redact values first and keep only the key names.

## Runtime port

Public Node services receive `PORT` from the runtime. Do not replace it with a hard-coded port; configure the application to listen on the provided value instead.

Typical correct patterns:

```ts
// Express / generic Node
const port = Number(process.env.PORT);
if (!Number.isFinite(port)) throw new Error("PORT is required");
app.listen(port, "0.0.0.0");
```

```js
// Next.js package.json — let the platform choose the port
{ "scripts": { "start": "next start -p $PORT" } }
```

Binding to `0.0.0.0` rather than `127.0.0.1` is part of the contract: NexHost verifies TCP reachability through the platform network, not a local loopback inside the container.

## Troubleshooting

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| Static site shows an old public URL after you updated a variable | Value was build-time and the site is still serving the previous artifact | Start a new deployment so a new build can inline the value. |
| Runtime crash: "PORT is required" or connection refused | Application hard-coded a port or did not read `process.env.PORT` | Read `PORT` at startup, bind to `0.0.0.0`, and redeploy. |
| Client bundle exposes a key you thought was secret | Variable had a client-side prefix (`NEXT_PUBLIC_`, `VITE_`) or was inlined into static output | Rename to a server-only key, scope to Runtime, and redeploy; rotate the exposed secret where it was issued. |
| Build succeeds locally but fails remotely with a missing variable | Scope was Runtime-only, so the build could not read the value | Change scope to Build or Both and redeploy. |

## Related documentation

- [Deployment Troubleshooting](/docs/deployments/troubleshooting) — diagnose build vs runtime failures from the detail page.
- [Logs](/docs/operations/logs) — read each deployment stage and share output safely.
- [Services Overview](/docs/services) — understand which service types even need a start command and `PORT`.

