# NexHost Documentation — Complete Corpus > Full public documentation for NexHost by Nexthomelabs. Generated 2026-09-21T07:55:39.612Z. Source: https://nexthomelabs.com/docs and https://nexthomelabs.com/llms.txt > This file is the combined machine-readable representation of public docs for AI consumption. No secrets or private data are included. > Machine-readable index: https://nexthomelabs.com/llms.txt — per-article Markdown: https://nexthomelabs.com/docs-md/{slug} --- ## Corpus map - NexHost Documentation — Choose a service, deploy code, and operate releases on NexHost. | Web: https://nexthomelabs.com/docs | Markdown: https://nexthomelabs.com/docs | Section: Getting Started - Getting Started — Create a project, choose the appropriate service type, and configure a first deployment. | Web: https://nexthomelabs.com/docs/getting-started | Markdown: https://nexthomelabs.com/docs-md/getting-started | Section: Getting Started - Your First Deployment — Deploy a project from a source archive or repository and verify the release in the dashboard. | Web: https://nexthomelabs.com/docs/getting-started/your-first-deployment | Markdown: https://nexthomelabs.com/docs-md/getting-started/your-first-deployment | Section: Getting Started - Services Overview — Select the NexHost service type that matches how your application runs. | Web: https://nexthomelabs.com/docs/services | Markdown: https://nexthomelabs.com/docs-md/services | Section: Create - Frontend Apps — Deploy a server-rendered Node.js frontend with its own public runtime and automatic listener discovery. | Web: https://nexthomelabs.com/docs/services/frontend-app | Markdown: https://nexthomelabs.com/docs-md/services/frontend-app | Section: Create - Static Sites — Publish pre-built HTML, CSS, JavaScript, and assets without a long-running application server. | Web: https://nexthomelabs.com/docs/services/static-sites | Markdown: https://nexthomelabs.com/docs-md/services/static-sites | Section: Create - Web Services — Run a public API or full-stack application that listens on an HTTP port. | Web: https://nexthomelabs.com/docs/services/web-services | Markdown: https://nexthomelabs.com/docs-md/services/web-services | Section: Create - Private Services — Run an internal service that is reachable by services in the same workspace network. | Web: https://nexthomelabs.com/docs/services/private-services | Markdown: https://nexthomelabs.com/docs-md/services/private-services | Section: Create - Background Workers — Run a long-lived process for queues, media processing, and asynchronous work. | Web: https://nexthomelabs.com/docs/services/background-workers | Markdown: https://nexthomelabs.com/docs-md/services/background-workers | Section: Create - Cron Jobs — Run a finite command on a UTC schedule. | Web: https://nexthomelabs.com/docs/services/cron-jobs | Markdown: https://nexthomelabs.com/docs-md/services/cron-jobs | Section: Create - Postgres — Provision a private PostgreSQL database with durable storage and generated connection credentials. | Web: https://nexthomelabs.com/docs/services/postgres | Markdown: https://nexthomelabs.com/docs-md/services/postgres | Section: Create - WordPress — Launch a managed WordPress site with private MySQL and persistent site content. | Web: https://nexthomelabs.com/docs/services/wordpress | Markdown: https://nexthomelabs.com/docs-md/services/wordpress | Section: Create - Workflows — Run an on-demand container task with run history, timeouts, and bounded retries. | Web: https://nexthomelabs.com/docs/services/workflows | Markdown: https://nexthomelabs.com/docs-md/services/workflows | Section: Create - Environment Variables — Configure build-time and runtime values for a NexHost service without committing them to source. | Web: https://nexthomelabs.com/docs/configuration/environment-variables | Markdown: https://nexthomelabs.com/docs-md/configuration/environment-variables | Section: Configure - Custom Domains — Attach a domain to a public NexHost service and complete the dashboard-guided DNS verification. | Web: https://nexthomelabs.com/docs/configuration/custom-domains | Markdown: https://nexthomelabs.com/docs-md/configuration/custom-domains | Section: Configure - Domains and Networking — Understand public and private service access before connecting applications. | Web: https://nexthomelabs.com/docs/configuration/networking | Markdown: https://nexthomelabs.com/docs-md/configuration/networking | Section: Configure - Deployments — Follow a NexHost release from source preparation through build, startup, and readiness. | Web: https://nexthomelabs.com/docs/deployments | Markdown: https://nexthomelabs.com/docs-md/deployments | Section: Operate - Deployment Troubleshooting — Diagnose source, build, startup, and TCP-readiness failures from the deployment detail page. | Web: https://nexthomelabs.com/docs/deployments/troubleshooting | Markdown: https://nexthomelabs.com/docs-md/deployments/troubleshooting | Section: Operate - Logs — Use deployment build output and service details to investigate a NexHost release. | Web: https://nexthomelabs.com/docs/operations/logs | Markdown: https://nexthomelabs.com/docs-md/operations/logs | Section: Operate - Storage and Release Artifacts — Understand the difference between immutable deployment artifacts and application data. | Web: https://nexthomelabs.com/docs/storage | Markdown: https://nexthomelabs.com/docs-md/storage | Section: Create - NextStorage Object Storage — Buckets, API keys, uploads, object URLs, and usage for NextStorage on NexHost. | Web: https://nexthomelabs.com/docs/storage/nextstorage | Markdown: https://nexthomelabs.com/docs-md/storage/nextstorage | Section: Create - Workspaces and Access — Keep project ownership, access, and support information organized within a NexHost workspace. | Web: https://nexthomelabs.com/docs/teams | Markdown: https://nexthomelabs.com/docs-md/teams | Section: Teams and Billing - Billing — Review workspace billing information and complete payment actions from the NexHost dashboard. | Web: https://nexthomelabs.com/docs/billing | Markdown: https://nexthomelabs.com/docs-md/billing | Section: Teams and Billing - Next CLI — Use the NexHost Git command-line interface to work with hosted repositories. | Web: https://nexthomelabs.com/docs/cli | Markdown: https://nexthomelabs.com/docs-md/cli | Section: Operate - NexHost Git — Create, clone, and connect a NexHost-hosted Git repository to a service. | Web: https://nexthomelabs.com/docs/git | Markdown: https://nexthomelabs.com/docs-md/git | Section: Operate - API Access and Availability — Understand the current supported programmatic interfaces for NexHost. | Web: https://nexthomelabs.com/docs/api | Markdown: https://nexthomelabs.com/docs-md/api | Section: Operate - Node.js Quickstart — Deploy a small Node.js HTTP application as a NexHost Web Service. | Web: https://nexthomelabs.com/docs/quickstarts/node | Markdown: https://nexthomelabs.com/docs-md/quickstarts/node | Section: Quickstarts - Python Quickstart — Deploy a Python HTTP application as a NexHost Web Service. | Web: https://nexthomelabs.com/docs/quickstarts/python | Markdown: https://nexthomelabs.com/docs-md/quickstarts/python | Section: Quickstarts - Static Sites Quickstart — Deploy a Vite, React, Astro, or exported Next.js frontend as a NexHost Static Site. | Web: https://nexthomelabs.com/docs/quickstarts/static-sites | Markdown: https://nexthomelabs.com/docs-md/quickstarts/static-sites | Section: Quickstarts - Docker Quickstart — Deploy an existing container image as a compatible NexHost runtime service. | Web: https://nexthomelabs.com/docs/quickstarts/docker | Markdown: https://nexthomelabs.com/docs-md/quickstarts/docker | Section: Quickstarts --- # NexHost Documentation > Choose a service, deploy code, and operate releases on NexHost. Source: https://nexthomelabs.com/docs Markdown: https://nexthomelabs.com/docs Slug: overview Section: Getting Started Keywords: nexhost, hosting, deployment, services, documentation, getting started Last updated: 2026-08-30 Reading time: 4 min read Headings: ## Why this documentation exists | ## Start here | ## The service model | ## How deployments work | ## Working safely | ## Where to go next --- # NexHost Documentation NexHost is the hosting platform by Nexthomelabs for teams that want to deploy websites, server-rendered frontends, APIs, internal services, scheduled jobs, databases, and one-off workflows from a single dashboard. Every capability is exposed as a **service** — a persistent definition of source, build instructions, runtime configuration, and release history — so deployments stay reproducible and observable. This documentation describes the service choices, controls, and workflows available in the NexHost dashboard. It is the canonical reference for how NexHost behaves: which service type to choose, what each deployment stage does, and how to connect domains and debug releases. ## Why this documentation exists NexHost optimizes for clarity over magic. When you select a service type, the platform applies a specific runtime model (static file delivery vs. long-running process vs. scheduled execution vs. managed database). Knowing that model up front prevents the most common deployment mistakes, such as uploading a server build as static files or hard-coding a port that the platform needs to inject. ## Start here These three pages give you a complete mental model in under ten minutes: - [Getting Started](/docs/getting-started) — the end-to-end dashboard flow from **Dashboard → New Project** through source, configuration, and deployment. Read this first if you have never shipped to NexHost before. - [Your First Deployment](/docs/getting-started/your-first-deployment) — a concrete walkthrough that takes a local folder or ZIP archive (or a Git repository) through a recorded release and verification on the generated hostname. - [Services Overview](/docs/services) — a decision table that maps what you are building to the exact service type that runs it. Skim this before you pick a service so you do not need a migration later. If you already know what you are building, jump directly to a quickstart: [Node.js](/docs/quickstarts/node), [Python](/docs/quickstarts/python), [Static Sites](/docs/quickstarts/static-sites), or [Docker](/docs/quickstarts/docker). ## The service model Each service has a **source**, **build or launch settings** (where applicable), and a **release history**. The selected service type controls whether NexHost serves static files, starts a public process, keeps a process private, runs it in the background, schedules it, or provisions a database or workflow. Think of a service as the declaration and a deployment as an immutable execution of that declaration: - A **Static Site** publishes an output directory such as `dist` or `out`. No process is started and no health check runs. - A **Frontend App** builds a Node.js project (for example Next.js with server rendering), then supervises its production server behind an automatically routed public hostname. - A **Web Service** runs a persistent public API or full-stack server with automatic TCP listener discovery. - A **Private Service**, **Background Worker**, or **Cron Job** runs code that is not directly exposed to the internet. - **Postgres** provisions a private database with durable storage and generated credentials. - A **Workflow** runs a single bounded container task with history, timeouts, and retries. For a framework with server-side rendering or runtime routes, use a [Frontend App](/docs/services/frontend-app). A static export belongs in a [Static Site](/docs/services/static-sites). APIs and full-stack backends belong in a [Web Service](/docs/services/web-services). The distinction matters: a static service cannot run a server, and a runtime service needs a persistent TCP listener rather than exported HTML. ## How deployments work Every deployment is recorded with its source commit or archive, resolved configuration, build output, and final status. The detail page for a deployment splits work into visible stages — source preparation, dependency installation, build, publish or startup, and (for runtime services) TCP readiness. That order is deliberate: when something fails, the failing stage tells you whether the problem is source selection, project configuration, or application behavior at startup. > [!TIP] > Treat the deployment detail page as your primary debugger. The first error line in the earliest failing stage is almost always the root cause; later warnings are usually consequences. ## Working safely Use the service configuration screen to review the source, commands, environment variables, and deployment history before each release. Two habits prevent most issues: 1. **Review before release.** Confirm branch, root directory, build and start commands, output directory, and environment variable scopes before you click deploy. 2. **Trust the dashboard as source of truth.** Build output and release status in the dashboard are authoritative when a deployment needs investigation. Local success does not guarantee the same commands, directory layout, or environment values ran remotely. Keep secrets out of repositories and archives — set them as environment variables in the dashboard instead. After a failure, read the build and release output from the first error upward; the most useful fix is usually the smallest precise change. ## Where to go next - New to NexHost? Follow [Getting Started](/docs/getting-started) → [Your First Deployment](/docs/getting-started/your-first-deployment). - Deciding a stack? Read [Services Overview](/docs/services) and then the specific service page. - Connecting a domain? See [Custom Domains](/docs/configuration/custom-domains) after your first successful public release. - Something failed? Start with [Deployment Troubleshooting](/docs/deployments/troubleshooting) and [Logs](/docs/operations/logs). --- # Getting Started > Create a project, choose the appropriate service type, and configure a first deployment. Source: https://nexthomelabs.com/docs/getting-started Markdown: https://nexthomelabs.com/docs-md/getting-started Slug: getting-started Section: Getting Started Keywords: getting started, project, service, deployment, new project Last updated: 2026-08-30 Reading time: 6 min read Headings: ## When to use this guide | ## Before you begin | ## Choose the right service | ## Add a source | ## Configure the release | ## Deploy and inspect | ## Common mistakes | ## Next steps --- # Getting Started You create a deployable unit on NexHost by opening **Dashboard → New Project** and working through three questions in order: *what kind of workload is this*, *where is the code*, and *how should it build and run*. The first answer — the service type — is the most consequential because it determines whether NexHost serves files, starts and verifies a process, schedules a command, or provisions a database. This guide gives you the complete flow once, so the rest of the documentation has a shared vocabulary: project, service, source, build, and release. ## When to use this guide Read this page when you are onboarding a new application, onboarding a teammate, or choosing between service types for the first time. You can skip ahead to [Your First Deployment](/docs/getting-started/your-first-deployment) if you already know which service type you need and just want the concrete archive-to-URL steps. ## Before you begin - A NexHost workspace you can access. The workspace scopes projects, services, repositories, domains, and billing. - Code that builds locally. Push or pack the same code you just verified — the platform will run the same build command remotely. - For public runtimes (Frontend Apps, Web Services): a persistent application that binds to `0.0.0.0`. NexHost supplies `PORT=3000` as a compatibility default and discovers the listener automatically. ## Choose the right service The dashboard asks for a service type **before** it asks for source and build details. That choice is important: it determines how NexHost starts, checks, and exposes your application. | If you are deploying… | Choose… | Why it exists | | --- | --- | --- | | HTML, CSS, JavaScript, or a framework static export | [Static Site](/docs/services/static-sites) | Serves pre-built files without running a server — cheap and fast for content-driven sites. | | Next.js, Nuxt, Remix, or another server-rendered UI | [Frontend App](/docs/services/frontend-app) | Runs a Node.js server behind a public hostname so SSR, middleware, and runtime routes work. | | An API, backend, or public full-stack server | [Web Service](/docs/services/web-services) | Runs a persistent public process with automatic listener discovery and ingress; the right home for backends. | | A service only other workspace services should reach | [Private Service](/docs/services/private-services) | Internal-only networking for service-to-service calls inside the workspace boundary. | | A continuous queue or asynchronous process | [Background Worker](/docs/services/background-workers) | A long-lived process that never serves traffic directly — ideal for consumers and processors. | | A command that runs and exits on a schedule | [Cron Job](/docs/services/cron-jobs) | A finite command on a UTC cron schedule, with exit-code-aware retries. | > [!WARNING] > Do not choose a service type based only on framework name. A Next.js project with `output: "export"` is a Static Site; the same project with server rendering is a Frontend App. Picking the wrong type is the single most common cause of confusing first-deployment failures. ## Add a source The source choices shown depend on the service type. They can include a local folder, ZIP archive, hosted NexHost Git repository, GitHub, GitLab, public Git URL, or an existing container image. Choose the branch and root directory when those controls are shown. What to expect by source: - **Local folder / ZIP archive** — fast for first tests. Pack only source and lockfiles; generated folders such as `node_modules`, `.git`, and local `.env*` files should stay out of the archive. - **NexHost Git repository** — first-class hosted Git. Create or clone via the [Next CLI](/docs/cli) or the dashboard, then push; select it as the source in New Project. See [NexHost Git](/docs/git) for the full flow. - **GitHub / GitLab / public Git URL** — connect an existing repository and pick the branch to track. - **Existing container image** — available for Web Services, Private Services, Background Workers, and Cron Jobs when the dashboard offers it. Useful when your build already happens elsewhere; see the [Docker Quickstart](/docs/quickstarts/docker). When the dashboard shows **Root directory**, verify it points at the package that contains the build manifest (for example the folder with `package.json` or `requirements.txt`). A mis-pointed root is a frequent cause of dependency-installation failures. ## Configure the release Set the build command, start command, output directory, and environment variables to match your application. Three rules cover most configurations: 1. **Runtime services must bind to `0.0.0.0`.** NexHost provides `PORT=3000` as a compatibility default, discovers the listener automatically, and assigns the external route. Static services publish the selected output directory instead of starting a server. 2. **Build outputs are not server processes.** Do not attempt to serve a server build directory (for example `.next`) as static files when the site needs server rendering. Choose the correct runtime type instead. 3. **Environment variables have scopes.** Build-time values are baked into the artifact; runtime values are provided at start. Changing a build-time variable requires a new deployment. See [Environment Variables](/docs/configuration/environment-variables) for the full scoping table. For runtime services, no health URL or public port is required. NexHost waits for a reachable TCP listener while the service starts. A process that binds only to `127.0.0.1`, exits immediately, or blocks before opening its server will not become ready. ## Deploy and inspect Start the deployment from the final review step. Follow the release in **Deployments** — the detail page splits output by stage so you can tell at a glance whether the failure was in source preparation, dependency installation, build, publish/startup, or TCP readiness. What success looks like: - The release row shows a successful status and timestamp. - For public services, the dashboard displays the generated hostname for your service. - Opening that hostname returns the expected content or JSON. What failure looks like: - A successful build followed by a failed startup readiness check almost always means the application bound only to localhost, exited immediately, or was blocked before opening a listener. These are application and configuration issues, not source issues. - Missing output or dependency errors during the build stage usually point to a wrong branch, root directory, or missing lockfile. A successful public service receives the hostname displayed by the dashboard; add a custom domain afterwards when needed — the domain flow runs after a public release succeeds. See [Custom Domains](/docs/configuration/custom-domains) when you are ready. ## Common mistakes - Selecting **Static Site** for a Next.js app that uses server rendering or API routes. Fix: recreate as a Frontend App. - Binding only to `127.0.0.1` instead of `0.0.0.0`. A fixed internal port such as `3000` is safe because each deployment has its own container network namespace. - Pointing the publish directory at a server build output (for example `.next`) rather than the static export (`out` or `dist`) or using a runtime service instead. - Changing an environment variable but not starting a new deployment for a static site, where the value is baked at build time. ## Next steps Continue with [Your First Deployment](/docs/getting-started/your-first-deployment) for a numbered, click-by-click walkthrough from local code to a verified public URL. If something did not behave as expected, [Deployment Troubleshooting](/docs/deployments/troubleshooting) maps symptoms to the exact setting to check. --- # Your First Deployment > Deploy a project from a source archive or repository and verify the release in the dashboard. Source: https://nexthomelabs.com/docs/getting-started/your-first-deployment Markdown: https://nexthomelabs.com/docs-md/getting-started/your-first-deployment Slug: getting-started/your-first-deployment Section: Getting Started Keywords: deployment, zip, git, release, frontend app, port, readiness Last updated: 2026-08-30 Reading time: 6 min read Headings: ## When to use this guide | ## Before you begin | ## 1. Prepare the project | ## 2. Create the service | ## 3. Configure runtime services | ## 4. Deploy and verify | ## What comes next --- # Your First Deployment This guide takes you from local code on your machine to a recorded, verifiable NexHost release you can open in a browser. It follows the dashboard path (**Dashboard → New Project**) and deliberately selects the service type **before** source configuration so the platform applies the right runtime model. You will finish with a project that has a release history, a build log, and — for public services — a hostname you can share. ## When to use this guide Use this flow the first time you ship an app to NexHost, when you are validating a new framework stack, or when you want a repeatable baseline before moving a team’s repository into the platform. If you already ship daily to NexHost, the same steps apply but you can select a repository source instead of a ZIP. ## Before you begin - A NexHost workspace and permission to create a project. - An application that builds locally with the production command you intend to use remotely. - For a server-rendered app or API, a persistent server that binds to `0.0.0.0`. NexHost supplies `PORT=3000` as a compatibility default and discovers the listener automatically. ## 1. Prepare the project Keep generated dependency folders and local secrets out of a source archive. For a static project, either upload source with a build command or an output folder that already contains `index.html`. For a server-rendered application, upload the **project source** and use a **Frontend App** rather than trying to serve `.next` or another server build as static files. A safe packaging command for a Node project: ```bash zip -r my-app.zip . -x "node_modules/*" ".git/*" ".env*" ``` What this does: - Includes source, configuration, and lockfiles so the platform can reproduce the install. - Excludes ephemeral or machine-specific state (`node_modules`, `.git` history, per-developer `.env` files) that bloat the archive and can hide the real build signal. For Python, Ruby, Go, or other stacks, the same principle applies: keep the archive limited to what your build command needs to recreate the output. In every case, do **not** commit or pack secrets — set them as environment variables in the dashboard instead. > [!TIP] > Run the same build command locally right before you archive. If it passes on your machine, the remote log is much easier to interpret when it does not — you already know the source was buildable in isolation. ## 2. Create the service 1. Open **Dashboard → New Project**. 2. Select the service type that matches the application — for example **Frontend App** for a Next.js app that uses server rendering, or **Static Site** for a Vite site you export as `dist`. 3. Choose the source method offered by that service. For this walkthrough, pick ZIP upload or local folder and attach the archive you just created. Other flows include NexHost Git, GitHub, GitLab, a public Git URL, or an existing container image when the dashboard offers it. 4. Select a stack when it matches your framework, then review the proposed commands. A stack is a starter preset; you remain responsible for the final values. For a Next.js application that uses server rendering, choose **Frontend App**, use the normal build command (`npm run build`), and set the start command to the application’s production start command (typically `npm run start`, which often resolves to `next start -p $PORT`). Do not use a build command as the start command — the runtime needs a long-lived server **after** the build completes. Double-check the **Root directory** when it is shown. It should point at the directory that contains the build manifest (`package.json`, `requirements.txt`, etc.). A repository with a frontend in `apps/web` and a backend in `apps/api` will fail if the root is left at the repository root. ## 3. Configure runtime services Runtime services need a process that accepts connections on the container interface. NexHost supplies `PORT=3000` as a compatibility default, discovers the TCP listener actually opened by the process, and assigns its own isolated ingress port. The host binding is the contract, not a user-entered port number or HTTP endpoint. For Node applications, the usual shape is: ```ts const port = Number(process.env.PORT); server.listen(port, "0.0.0.0"); ``` For Express, Next.js with a custom server, Koa, or Fastify, the same idea applies: ```js const port = Number(process.env.PORT); app.listen(port, "0.0.0.0", () => { console.log(`Listening on ${port}`); }); ``` For Flask or FastAPI behind `gunicorn`/`uvicorn`, pass the value through the start command: ```bash # Flask gunicorn app:app --bind 0.0.0.0:$PORT # FastAPI uvicorn app:app --host 0.0.0.0 --port $PORT ``` NexHost does not require you to add or configure a health URL. It waits for a reachable TCP listener during startup, then routes the final container through a unique internal Docker port. You may still provide a `/health` endpoint for your own clients or monitoring, but it is not part of the deployment contract. ## 4. Deploy and verify Start the deployment from the review screen. The deployment detail page shows source preparation, dependencies, build, and release status in order. Each row has a timestamp and output so you can distinguish a build failure from a runtime one. **Expected outcome for a successful release:** - The deployment status becomes successful. - For public services, the dashboard shows a generated hostname for that service. - Opening the hostname loads the application page once NexHost has detected and routed its listener. **If the deployment stops during startup readiness, confirm all of the following before changing anything else:** - The selected service is **Frontend App** or **Web Service**, not a Static Site. A static service never starts a process, so it cannot satisfy runtime startup readiness. - The start command starts a persistent process (for example `npm run start` / `next start -p $PORT` for Node, `gunicorn … --bind 0.0.0.0:$PORT` for Python). A bare build command (`npm run build`) starts nothing and the release will always time out. - The process binds to `0.0.0.0`, not only to `127.0.0.1`. It may use `process.env.PORT`, which defaults to `3000`, or its normal fixed internal port. Each container has its own network namespace, so two services can safely use `3000`. - The process reaches its server listen call after required initialization. A database connection that never resolves, or a start command that launches only a build, prevents NexHost from discovering the listener. > [!NOTE] > Change one deployment input at a time. For a startup failure, begin with the start command and application binding; this makes the next deployment log much easier to compare. See [Deployment Troubleshooting](/docs/deployments/troubleshooting) for a guided, symptom-by-symptom diagnosis, or [Logs](/docs/operations/logs) for how to read each stage’s output without sharing secrets. ## What comes next - Add a persistent database with [Postgres](/docs/services/postgres) and wire the connection string as an environment variable on the application service. - Attach a real hostname after the first successful public release: [Custom Domains](/docs/configuration/custom-domains). - Move from archive uploads to hosted source: [NexHost Git](/docs/git) and the [Next CLI](/docs/cli). - Understand pricing and workspace scope: [Workspaces and Access](/docs/teams) and [Billing](/docs/billing). --- # Services Overview > Select the NexHost service type that matches how your application runs. Source: https://nexthomelabs.com/docs/services Markdown: https://nexthomelabs.com/docs-md/services Slug: services Section: Create Keywords: services, static site, frontend app, web service, worker, cron, postgres, workflow Last updated: 2026-08-30 Reading time: 5 min read Headings: ## The catalog at a glance | ## How to choose between the public options | ## Sources and stacks | ## The Frontend App distinction | ## Related documentation --- # Services Overview NexHost service types separate static delivery, user-facing Node frontends, public APIs, private processes, background work, scheduled commands, databases, and one-off tasks. Choose the type based on the **process you need to run** — not just the framework name — because each type applies a different runtime contract (no process, an automatically routed public server, a private server, a long-running worker, a finite schedule, a managed database, or a bounded container task). Picking the right type on creation is cheaper than migrating later: the dashboard’s automatic listener discovery, network exposure, and execution model all branch from that first choice. ## The catalog at a glance | Service type | Use it for | Public URL? | Lifecycle | | --- | --- | --- | --- | | [Static Site](/docs/services/static-sites) | Pre-built files with no running application server (plain HTML, Vite `dist`, Astro `dist`, Next.js `out` with `output: "export"`, SvelteKit `build`) | Yes — files are served directly | Built once per deployment; no process | | [Frontend App](/docs/services/frontend-app) | Server-rendered Node.js user interfaces with a public URL (Next.js SSR, Nuxt server, Remix, SvelteKit server) | Yes — a Node server is supervised and automatically routed | Built, then a persistent server opens a TCP listener | | [Web Service](/docs/services/web-services) | Public APIs and full-stack application backends | Yes — same public-runtime model as Frontend App, but for backends | Built, then a persistent server listens on `PORT` | | [Private Service](/docs/services/private-services) | Internal services reachable only from inside the workspace network | No — workspace-private | Runtime server on an internal host/port, configured like a Web Service | | [Background Worker](/docs/services/background-workers) | Long-running queue consumers and asynchronous work | No — no external port is exposed | Long-lived process that must stay up; env-driven retries | | [Cron Job](/docs/services/cron-jobs) | Scheduled commands that finish and exit | No — executed by the scheduler | Finite command on a 5-field UTC cron; exit code signals success | | [Postgres](/docs/services/postgres) | A private PostgreSQL database with durable storage | No — workspace-private | Managed database; credentials generated for the workspace | | [Workflow](/docs/services/workflows) | An on-demand container task with run history, timeouts, and retry limits | No — single-shot | Bounded container execution on demand | Short prompts for the common decisions: - **Content or marketing pages that build to files** → Static Site. - **A Next.js / Nuxt / Remix UI that needs a running server** → Frontend App. - **An API, a mixed full-stack backend, or anything that answers browser + mobile + webhooks** → Web Service. - **Service-to-service APIs inside one workspace** → Private Service. - **Continuously running processors** → Background Worker. - **A command that should have finished already** → Cron Job. ## How to choose between the public options The three public host types look similar, but they serve different products: - **Static Site** knows no notion of runtime listener discovery. It uploads a directory and serves it. There is no process to crash. - **Frontend App** and **Web Service** both start a process, bind to `0.0.0.0`, and have their TCP listener discovered automatically. Frontend App is the **dedicated UI runtime**; Web Service is the **general backend runtime**. The distinction exists so reviewers and on-call engineers can tell at a glance which service owns the user interface. > [!TIP] > If a build can produce both a static folder and a server (for example Next.js), ask: *does any page, route, or feature require runtime execution* — server rendering, API routes, middleware, `next/image` optimization? If the answer is yes for even one path, choose a runtime type (Frontend App for a UI, Web Service for a backend), not a Static Site. ## Sources and stacks Static Sites and Frontend Apps accept repository and archive sources. Web Services, Private Services, Workers, and Cron Jobs can also use an existing image when the dashboard offers it — useful when your build already happens elsewhere. See the [Docker Quickstart](/docs/quickstarts/docker) for the image flow. The selected **stack** supplies a starting configuration — build command, start command, and output expectations for a given framework or language. It is a starting point, not a lock-in. Review every command, directory, and environment variable before deployment. A stack that assumed `npm run build → dist` will misfire when pointed at a Python project or a monorepo with a different layout. ## The Frontend App distinction A **Frontend App** is a dedicated public Node.js runtime for UI applications such as Next.js, Nuxt, Remix, and SvelteKit with server output. It is not a backend API service, although it uses the same public-runtime essentials: a start command and a listener bound to `0.0.0.0`. Use a Web Service when the product’s primary job is an API or general backend. The split is organizational clarity, not technical necessity. Keeping frontends and backends on named, distinct runtimes makes the workspace layout self-documenting — future teammates can read the service list and know immediately which hostname renders the UI and which answers the API calls. ## Related documentation - [Getting Started](/docs/getting-started) — the full create → source → build → deploy flow. - [Your First Deployment](/docs/getting-started/your-first-deployment) — numbered archive-to-hostname walkthrough. - [Domains and Networking](/docs/configuration/networking) — public vs private access after the first successful release. - [Deployments](/docs/deployments) and [Deployment Troubleshooting](/docs/deployments/troubleshooting) — reading stage output when something fails. --- # 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 Keywords: frontend app, next.js, node.js, ssr, TCP readiness, port Last updated: 2026-08-30 Reading time: 6 min read Headings: ## When to use — and when not to | ## How it differs from a Static Site | ## Before you begin | ## Configure a Node frontend | ## TCP readiness | ## Deploy | ## Troubleshooting | ## Common mistakes | ## Related documentation --- # 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. --- # 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 Keywords: static site, vite, react, astro, next export, publish directory, build Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use — and when not to | ## Common output directories | ## Next.js static export | ## Environment variables and build-time inlining | ## Deploy | ## Troubleshooting | ## Related documentation --- # 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. --- # Web Services > Run a public API or full-stack application that listens on an HTTP port. Source: https://nexthomelabs.com/docs/services/web-services Markdown: https://nexthomelabs.com/docs-md/services/web-services Slug: services/web-services Section: Create Keywords: web service, api, backend, node.js, port, readiness, full stack Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use — and when not to | ## Required runtime behavior | ## Configure and deploy | ## How readiness reports | ## When to choose Frontend App instead | ## Troubleshooting | ## Related documentation --- # Web Services Choose **Web Service** for public APIs, application backends, and full-stack servers that need to listen on a network port. It starts a persistent process behind a public URL, discovers its TCP listener, and assigns isolated Docker ingress before the release becomes ready. A Web Service is intentionally general-purpose: Express, Fastify, Koa, NestJS, Django, Flask, FastAPI, Go’s `net/http`, and similar servers all fit. The process must keep running and bind to `0.0.0.0` so it is reachable from the container network. ## When to use — and when not to **Use Web Service when:** - The deliverable is an API server, a full-stack server that mixes API routes and UI, or any backend that needs an HTTP port and public hostname. - Multiple clients (browser, mobile, third-party webhooks) will call the same service. - You want external HTTP ingress and release-gated TCP readiness without running your own reverse proxy. **Do not use Web Service when:** - The deliverable is a pure server-rendered UI such as Next.js with SSR or a Nuxt server — use [Frontend App](/docs/services/frontend-app) so the frontend execution model is explicit in the project. - The process should not be reachable from the public internet — use [Private Service](/docs/services/private-services). - The work is a long-lived queue consumer (use [Background Worker](/docs/services/background-workers)) or a schedule-driven task that finishes and exits (use [Cron Job](/docs/services/cron-jobs)). ## Required runtime behavior Your application must start successfully and listen on a TCP port bound to `0.0.0.0`, not only to localhost. NexHost provides `PORT=3000` as a compatibility default and automatically discovers the port the process actually opens. Each service is isolated in its own container, so many services may safely use `3000` internally. A Node server normally follows this pattern: ```ts const port = Number(process.env.PORT); if (!Number.isFinite(port)) throw new Error("PORT is required"); app.listen(port, "0.0.0.0", () => { console.log(`Listening on ${port}`); }); ``` The same two lines appear across stacks: ```bash # Python — gunicorn gunicorn app:app --bind 0.0.0.0:$PORT # Python — uvicorn (FastAPI) uvicorn app:app --host 0.0.0.0 --port $PORT # Go # listen on :${PORT} ``` NexHost does not ask for a health path and does not fetch a customer URL during deployment. It waits for the container’s listener to become reachable, then creates the public route. You may keep a `/health` endpoint for external monitoring, but it is not required to deploy. > [!WARNING] > You can use `process.env.PORT` or a fixed internal port such as `3000`; NexHost discovers it. Binding only to `127.0.0.1` is not supported because the runtime must reach the service through the container network. ## Configure and deploy 1. **Select source.** Choose a supported source — a repository, ZIP archive, local folder, public Git URL, or an existing container image when the dashboard offers it. Confirm the branch and root directory. 2. **Configure commands.** Enter the build and start commands for the project. A Node service typically uses `npm ci`/`npm install` for install and `npm run build` for build; the Start command must keep a process alive (for example `npm start`). 3. **Set environment variables.** Add secrets and configuration with the right scope — runtime values (database URLs, tokens) should be scoped to Runtime or Both. See [Environment Variables](/docs/configuration/environment-variables). 4. **Deploy and verify.** NexHost detects the listener and allocates ingress automatically. On success the service gets a public hostname. Use the build log to diagnose dependency or build failures, and the deployment details to distinguish a successful build from an application startup failure. A clean build followed by a readiness timeout is usually a start-command, binding, or application-initialization problem rather than source. ## How readiness reports The deployment detail page splits the release into stages for exactly this reason: - **Source / Dependencies / Build** — did we prepare and compile the code? - **Publish or start** — did the output directory exist and did the process launch? - **TCP readiness** — did the process open a listener that NexHost could reach through the container network before the startup deadline? When a bug report says "the build passed but the URL does not load," the answer is almost always in the startup-readiness stage. Compare one deployment’s start command and binding behavior to the next, changing only one input between attempts. ## When to choose Frontend App instead Use [Frontend App](/docs/services/frontend-app) when the service is primarily a server-rendered user interface. Both types are public Node runtimes and both require a start command and a listener bound to `0.0.0.0`, but the dedicated Frontend App choice makes the frontend execution model explicit in the project workflow and helps reviewers and on-call engineers reason faster about which service owns the UI. ## Troubleshooting | Symptom | Check | | --- | --- | | Startup readiness times out | The process must remain alive, reach its server listen call, and bind to `0.0.0.0`. Run the same start command locally and confirm the server opens a TCP listener. | | Connection refused | Binding to `127.0.0.1` rather than `0.0.0.0` is the most common variant. | | Build passes, app instantly exits | The start command builds rather than runs (`npm run build` instead of `npm start`), or initialization is blocked by an unavailable dependency. | See [Deployment Troubleshooting](/docs/deployments/troubleshooting) and [Logs](/docs/operations/logs) for systematic reading of each stage’s output. ## Related documentation - [Frontend Apps](/docs/services/frontend-app) — dedicated UI runtime on the same public-runtime foundation. - [Private Services](/docs/services/private-services) — when the same runtime behavior belongs only to the workspace network. - [Environment Variables](/docs/configuration/environment-variables) — scoping so build-time and runtime secrets arrive in the right phase. - [Domains and Networking](/docs/configuration/networking) — public vs private access models. --- # Private Services > Run an internal service that is reachable by services in the same workspace network. Source: https://nexthomelabs.com/docs/services/private-services Markdown: https://nexthomelabs.com/docs-md/services/private-services Slug: services/private-services Section: Create Keywords: private service, internal service, workspace network, TCP readiness Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use — and when not to | ## Configure it like a runtime service | ## Connect from other services | ## Troubleshooting | ## Related documentation --- # Private Services A **Private Service** is a persistent application that does **not receive a public URL**. Use it for internal APIs, internal webhooks, service-to-service RPC endpoints, and application components that should only be called by services in the same workspace network. It is the counterpart to a Web Service when the intended callers are inside the workspace rather than on the internet. Choosing "private" is a network decision, not an authentication decision: an internal service protected only by a shared bearer token but still reachable from the public internet does not offer the same tenancy isolation as a service that has no public ingress at all. ## When to use — and when not to **Use Private Service when:** - The consumer is another NexHost service in the **same workspace** — for example an API called only by your Frontend App, a webhook processor other workers invoke, or a BFF (backend-for-frontend) that your worker pool internalizes. - The API manages workspace-internal concerns (job orchestration, service-mesh control, internal event ingestion) that external users must not invoke directly. - You want the workspace boundary to be the network boundary — code in a different workspace must not reach the internals. **Do not use Private Service when:** - The caller is a browser, mobile app, or third-party webhook on the public internet — ship a [Web Service](/docs/services/web-services) and enforce application-level authentication there. - The work is a long-lived queue consumer (use [Background Worker](/docs/services/background-workers)) or a scheduler-controlled on-demand run (use [Cron Job](/docs/services/cron-jobs) / [Workflow](/docs/services/workflows)). If the service serves both callers (an API that external apps call, plus one endpoint that only workspace services call), decompose: keep the external surface on a public service and the internal surface on a private one, each with the minimal needed environment variables. ## Configure it like a runtime service From a configuration standpoint, a Private Service is a sibling of a Web Service: it needs a **source**, **build** and **start commands** when they apply, and any **required environment variables**. NexHost discovers a reachable TCP listener during startup even though the result is not a public hostname. 1. **Choose a source.** Select a supported repository, archive, folder, or an existing image when the dashboard offers it. Confirm the branch and root directory for that source. 2. **Set build and start commands.** The build produces the artifact the platform will attempt to start; the start command keeps the process alive. A continuous `npm start`, `gunicorn …`, or binary invocation are common. 3. **Configure environment variables.** Wire database URLs, inter-service credentials, and queue endpoints as scoped secrets. Keep them out of source — the same scoping rules that apply to public runtimes apply here. 4. **Bind the process to `0.0.0.0`.** NexHost discovers the private listener automatically; no health path or port setting is required. Keep credentials and service connection details in the **workspace configuration** rather than committing them to source. A service definition committed to a repository that contains connection parameters is still history that must be rotated. > [!TIP] > Validate readiness locally before you deploy. Run the same start command with the same environment values and confirm that it opens a TCP listener on `0.0.0.0`. ## Connect from other services The dashboard provides the private service’s **connection details in its service configuration** — the internal host, port, connection string, or workspace-scoped URL as appropriate for the runtime type. Use **those displayed details** from the other services in the **same workspace**. Reading the correct value matters: - A workspace-private address is not a hostname you memorize; it is the address the deployment currently advertises. A redeployment or infrastructure operation can change it, so prefer reading it at configuration time rather than caching it in application documentation. - Cross-workspace access is not expected to succeed even when the workspace names feel similar. Treat the workspace as the addressing boundary. Do not expect a private service to be reachable directly from the public internet. Probing it from an external browser, `curl` outside the workspace, or a third-party webhook will fail by design — use an external-service measurement (the calling workspace service’s logs, not a public-network `curl` from your laptop) to verify connectivity. ## Troubleshooting | Symptom | Likely cause | Fix | | --- | --- | --- | | Calling service reports `ECONNREFUSED` to the private address | The private service never entered `ready` — check its deployment detail (build or startup/launch failure) before blaming the network | Open the private service’s last deployment; read the stage output from the first error upward | | `401/403` on a private API call | The application route is protected; the caller did not send the application credential | Pass the application authentication header between services; this is separate from NexHost TCP readiness. | | Intermittent failure only on first call after deploy | Transition/cold-start window on first readiness | Keep startup cheap; avoid synchronous external calls in the startup path | ## Related documentation - [Web Services](/docs/services/web-services) — the public counterpart when external callers must reach the API. - [Background Workers](/docs/services/background-workers) — long-lived consumers with a similar "stay alive" contract but no HTTP ingress. - [Environment Variables](/docs/configuration/environment-variables) — scope credentials so build and runtime see the right values. - [Domains and Networking](/docs/configuration/networking) — the public vs private split and how listener discovery fits. - [Deployments](/docs/deployments) / [Logs](/docs/operations/logs) — diagnose why a private service never reported ready. --- # Background Workers > Run a long-lived process for queues, media processing, and asynchronous work. Source: https://nexthomelabs.com/docs/services/background-workers Markdown: https://nexthomelabs.com/docs-md/services/background-workers Slug: services/background-workers Section: Create Keywords: background worker, queue, asynchronous, worker, long-lived process Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use — and when not to | ## Configure the process | ## Observe releases | ## Related documentation --- # Background Workers Choose **Background Worker** for a process that **should remain running but does not serve a public HTTP application** directly. Typical uses include queue consumers, media transcoding pipelines, event handlers, continuous synchronization loops, and any asynchronous workload whose job is not "accept an HTTP GET and prove itself healthy," but "keep pulling work and making progress." A worker is not a Web Service with a hidden port — it has **no public URL**. Selecting the correct service type aligns the deployment’s lifecycle with the process’s semantics: the platform watches for whether the process stays alive, not whether a public HTTP path is ready. ## When to use — and when not to **Use a Background Worker when:** - The process consumes from a queue or stream continuously (for example an AMQP-compatible queue, cloud queues, or internal task tables) and should retry and back off in the application’s own job logic. - The work is long-lived and stateful across many items (media processing, index building, event propagation) and there is no natural "request" that defines a timeout. - There is no external client that needs an HTTP endpoint; the worker’s only interface is the queue it reads and whatever datastore it writes to. **Do not use a Background Worker when:** - The work is naturally **scheduled and finite** — a single command that should run once per hour, per day, or per window and then **exit**. Use [Cron Job](/docs/services/cron-jobs) instead when the work is bounded by a clock. - The work is an **on-demand bounded container task** that needs a retry limit, a formal timeout, and per-run history (for example a one-off import or a per-invoice render). Use [Workflow](/docs/services/workflows). - The deliverable **serves traffic** and must be reachable on a hostname — use [Web Service](/docs/services/web-services) or [Frontend App](/docs/services/frontend-app). > [!INFO] > A queue consumer that stays up for hours is a Worker; a nightly reconciliation script that has finished once it prints the report is a Cron Job. The question is not how much work there is, but whether there is a reader that should stay open. ## Configure the process Set the **source** and **start command** that keeps the worker running — the start command is the whole process definition here, not a complement to a health path: - **Source** — a repository, ZIP archive, or folder (and, when the dashboard offers it, an existing container image — see the [Docker Quickstart](/docs/quickstarts/docker)). Confirm the branch and root directory for that source. - **Start command** — the statement that stays alive. Typical forms: `node worker.js`, `python -m myapp.worker`, `sidekiq`, `celery -A proj worker`, a custom binary invocation, or an `npm run worker` that encodes the same. - **Environment variables** — configure connection strings, credentials, and queue settings as scoped secrets in the dashboard. The scope guidance in [Environment Variables](/docs/configuration/environment-variables) applies identically to workers: a variable needed only at runtime should not ride in a build-scoped place. A worker should **handle retries and failures in its own job logic**. The platform observes the process lifecycle and deployment history, but per-message retry, dead-lettering, and idempotency are application concerns. Common patterns: - Fetch → attempt → ack or requeue with backoff, with a bounded retry count and a dead-letter queue for the surprising failures that need human eyes. - Lease per-message visibility so a duplicate lease does not double-process when a previous lease had not yet timed out. - Record progress externally (database row, queue offset) so restarts pick up from the last acknowledged item rather than from the beginning. > [!WARNING] > A start command that **completes** rather than stays up (`python import_once.py` that prints the report and exits) belongs in a Cron Job or Workflow, not a Worker. That distinction determines whether a "success" means "finished once" or "still consuming." ## Observe releases Use the **deployment detail page** to inspect **source preparation, dependency installation, and startup state** — the same stages runtime services show, minus the public health probe. If a worker exits unexpectedly, review the start command and its **application output** before redeploying. Day-to-day reading: - The detail page shows the underlying commit or archive name, the resolved configuration, and the staged text output in order. When the worker’s log ends with a successful exit code rather than a crash, it probably ran the wrong command. - Framework detection and environment snapshot ride with the release record, so two releases that differ only in an environment variable are distinguishable without reconstructing a commit history. - Process restarts are visible in application output — a crash that loops is not the same as a commit that never built. > [!TIP] > Locally reproduce worker behavior with the same command you configure in the dashboard. A behavior invisible to HTTP (`sleep 1; exit 0`) is a full-day bug when placed in a long-lived process definition — catch it before the platform does. ## Related documentation - [Cron Jobs](/docs/services/cron-jobs) — when work is clock-scheduled and finite. - [Workflows](/docs/services/workflows) — on-demand bounded tasks with explicit timeouts and retry limits. - [Logs](/docs/operations/logs) — reading stage output and application text for a process with no public health check. - [Deployments](/docs/deployments) and [Deployment Troubleshooting](/docs/deployments/troubleshooting) — diagnosing dependency and startup failures from the detail page. - [Environment Variables](/docs/configuration/environment-variables) — scoping so queue credentials and app configuration arrive where they are needed. --- # Cron Jobs > Run a finite command on a UTC schedule. Source: https://nexthomelabs.com/docs/services/cron-jobs Markdown: https://nexthomelabs.com/docs-md/services/cron-jobs Slug: services/cron-jobs Section: Create Keywords: cron, scheduled job, utc, task, schedule Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use — and when not to | ## Schedule and command | ## Good job behavior | ## Observing runs | ## Related documentation --- # Cron Jobs A **Cron Job** starts a command on a schedule, performs a **finite task, and exits**. That finality is the whole point of the service type: the platform measures success by exit code, and the dashboard records per-run history rather than watching for a long-lived process. Use Cron Jobs for reports, cleanup, data imports, periodic credential rotation, cache warming, newsletter generation, and other synchronization tasks — anything that is naturally described as "run this command at midnight, and when it is done, it is done." For a process that must stay online continuously, choose a [Background Worker](/docs/services/background-workers). For an on-demand container task that already carries a formal timeout and retry limit, choose a [Workflow](/docs/services/workflows). ## When to use — and when not to **Use a Cron Job when:** - The task is bounded by time rather than by a queue: nightly email exports, hourly metric rollups, daily provider syncs, weekly pruning. - The natural success signal is an exit code — `0` means done, non-zero means the run failed and should be retried or investigated. - The schedule is reasonably described as a cron pattern, not as an event. **Do not use a Cron Job when:** - The process must **stay alive** continuously, consuming from a queue or stream — use a Background Worker. - The deliverable is an HTTP service — use [Web Service](/docs/services/web-services) or [Frontend App](/docs/services/frontend-app). - The task has nuanced input-by-input retry and timeout expectations better described as a bounded container invocation — use a Workflow. ## Schedule and command Choose **Cron Job** in **New Project**, configure a supported source or image, set the **command**, and enter a **standard five-field cron expression**. NexHost schedules cron jobs in **UTC**, so convert business-time requirements before saving the schedule. The canonical fields — with no extension: ```text * * * * * │ │ │ │ └─ day of week (0–7, both 0 and 7 mean Sunday) │ │ │ └──── month (1–12) │ │ └─────── day of month (1–31) │ └────────── hour (0–23, UTC) └───────────── minute (0–59) ``` Practical examples at the dashboard boundary (UTC): | You want | Cron expression | Note | | --- | --- | --- | | Every hour at the top of the hour | `0 * * * *` | Good probe for "is the pipeline still progressing?" | | Daily at 02:00 UTC | `0 2 * * *` | Convert your local-time requirement to UTC — e.g. "02:00 Europe/Berlin in UTC" means a different hour in winter versus summer due to DST. | | Every Monday at 06:15 UTC | `15 6 * * 1` | Great for weekly rollups; verify the day mapping against the help tooltip for the dashboard. | | Every 10 minutes | `*/10 * * * *` | High-frequency polling belongs in a Worker if the cadence is about "keep reading," not "run this discrete report." | > [!WARNING] > The platform makes the decision on UTC. Do not author the expression for your wall-clock time zone and assume it will track local daylight changes — convert once, label it in the schedule’s description if your process description holds that context, and verify the first invocation’s logged UTC timestamp matches the converted time. The **command** itself follows the same source conventions as other runtime services: for a repository/archive source the dashboard expects a command string that makes sense at the project’s root (for example `python scripts/cleanup.py` or `node scripts/import.js`). For an existing-image source, the image’s entrypoint may be the command, with these settings as its arguments. Inspect the deployment detail after the first scheduled run — some images expose the effective `CMD` as it was assembled, which is faster than re-deriving it from `Dockerfile` history. ## Good job behavior A well-behaved cron job is one your future on-call can diagnose from one run’s output and can safely retry after a partial failure. - **Make each run safe to retry.** Structure the operation to be **idempotent** — re-running the same command with the same input should not double-count, double-bill, or synthesize duplicate side effects. Prefer "process every unprocessed row" over "process row N" where possible, and guard external mutations with idempotency keys. - **Exit with a non-zero code on failure.** The platform reports exit status per run in history. A job that exits `0` even when the write failed reads as successful in history and will not draw attention when it silently stops delivering value. Let expected errors bubble to a non-zero exit. - **Write actionable application output.** Print what the run consumed, what it produced (count of processed items, skipped items, and failures), and where a retried run would start. Future diagnostics — and the diff between two runs — benefit more from that ledger than from verbose debug noise. - **Keep per-run dependencies lean.** A nightly import that hits an external provider once at startup and then reuses the connection is cheaper than one that establishes N connections inside N iterations. In low-resource contexts this is also friendlier to shared-host limits. Use a [Background Worker](/docs/services/background-workers) for queue consumers or any process that **should not exit after a single run** — a worker that has a schedule to retry after a transient error long before the next cron tick belongs on a continuous process. > [!TIP] > Simulate the schedule locally with a single manual run: `cron_expression="0 2 * * *" python scripts/cleanup.py --dry-run` or your language’s equivalent scheduler harness. Observing idempotent output on a second run in the same checkout outs the class of bugs that midnight-only invocation would hide. ## Observing runs The **deployment detail / service history** records each cron invocation, its inputs (per the source that was recorded for the deployment), the command as configured, the exit code, and the captured application output. Inspect a **failed run before retrying** so a configuration or input problem is not repeated automatically — especially for destructive jobs such as cleanup or migration, where re-running the same bad inputs compounds harm. ## Related documentation - [Background Workers](/docs/services/background-workers) — continuous consumers when "staying alive" is the correct model. - [Workflows](/docs/services/workflows) — on-demand bounded container tasks with explicit timeout and retry limit. - [Logs](/docs/operations/logs) — reading stage output and application lines for a scheduled rather than an HTTP-triggered service. - [Deployments](/docs/deployments) — per-run provenance and comparison after the next run. --- # Postgres > Provision a private PostgreSQL database with durable storage and generated connection credentials. Source: https://nexthomelabs.com/docs/services/postgres Markdown: https://nexthomelabs.com/docs-md/services/postgres Slug: services/postgres Section: Create Keywords: postgres, postgresql, database, connection string, private database, durable storage Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use — and when not to | ## Connect an application | ## Operations | ## Troubleshooting | ## Related documentation --- # Postgres Choose **Postgres** to provision a **private PostgreSQL database** for services in your workspace. The service creation flow sets aside durable storage for that database and surfaces generated connection credentials scoped to the workspace. The database is reachable only from workspace services — it is never given a public hostname — which aligns its production boundary with the applications that read from it. This integration is intentionally minimal: Postgres is there to persist what your service treats as durable rows — orders, users, sessions with durability — rather than to replace application-file storage or blob storage. ## When to use — and when not to **Use Postgres when:** - The deliverable needs durable relational rows: users, orders, credits, entitlement records, job metadata. - Multiple services in the workspace should read and write the same domain data. - You benefit from transactional guarantees and typed, relational shape rather than bespoke file persistence. **Do not use Postgres when:** - The state is ephemeral and safe to lose on restart (in-memory cache, transient job numbering) — consider whether durability is actually required. - A static-only service (a site with no process) requests "a database attached to the deployment" — static artifacts are files, not running servers with a persistent connection lifecycle; keep data where a service that runs a process can own it. - Blob and object storage is the primary need — create the application-owned persistence decision alongside the database and wire each explicitly rather than coalescing everything through rows. ## Connect an application Create the database **first**, then copy its **displayed connection details** into the **environment configuration** of the service that needs to talk to it. A reliable ordering: 1. In **New Project**, choose **Postgres**. The creation flow allocates storage and shows the generated connection credentials — often as a single connection string (URL form) or as a `host / port / database / username / password` set. Treat that screen as authoritative for that release of the database; it can change between revisions and should not be memorized. 2. Open the **service** that will read from the database (for example a Web Service or Background Worker). 3. Add the connection string as an **environment variable** on that service. **Treat the connection string as a secret**: scope it to Runtime (or Both only when the application’s build legitimately needs to read it), do not prefix it with a browser-exposed prefix such as `NEXT_PUBLIC_` or `VITE_`, and do not commit it. 4. In application code, read the variable from the environment at startup and establish the connection. The exact client library shape differs by language, but the pattern is the same: ```ts // Node example (any PostgreSQL client) const connectionString = process.env.DATABASE_URL; if (!connectionString) throw new Error("DATABASE_URL is required"); const pool = new Pool({ connectionString }); ``` Do not put the connection string in browser code or commit it to a repository — that exposure preserves the secret in history even after you rotate it. Similarly, avoid placing it in logs, issue text, or shared deployment screenshots. The deployment detail records that a connection *is configured*; the value itself stays workspace-private. > [!TIP] > Pulte that the build that ran with a previous value no longer represents the same `DATABASE_URL`? Deploy again after rotating the secret so the next release’s observed environment and logs are consistent with the rotated value. Stale environments reading cached credentials produce confusing cross-mismatch logs. ## Operations Manage the database through its **project and service screens** — the same place you created it. Day-to-day operations fall into three categories: - **Connection and secrets hygiene.** Rotate the credential the moment it was ever captured into a log, screenshot, or repository. The application must then pick up the rotated value on its next deployment; keep the old and new environment values coordinated so the roll does not leave the app pointing at the previous secret. - **Schema and migrations.** Run migrations from the service that owns the connection — usually as a deployment-gated build/start step or an explicit migration invocation against the value stored in the environment. A migration that fails mid-transaction should be retried following the application’s idempotent migration policy, not by re-provisioning the database. - **Data lifecycle and backup.** Before making **destructive schema or data changes** — `DROP`, mass `DELETE` or `UPDATE` without tight predicates, major index rebuilds on large tables — create and **verify a backup plan appropriate for the application**. The platform provenance around each deployment (time, build, launching config snapshot) is independent of the backup strategy you choose for rows — they are separate layers. > [!WARNING] > Do not use the deployment artifact as the data store. Putting uploads or mutable state into the image filesystem or the static publishing directory is not durable — the next successful release can replace it. ## Troubleshooting | Symptom | Likely cause | Fix | | --- | --- | --- | | `password authentication failed` | The application still reads a previously rotated connection string, or the environment variable was scoped so it never reached the runtime | Confirm the database’s current displayed credentials, the variable’s scope, and redeploy the application service so the new environment is active. | | Connection timeout | The caller is not a workspace service, or the connection detail was taken from a previous revision | Read the current connection details from the database screen and check which workspace the caller lives in. | | Build succeeds but migration/start fails | The migration retries are not idempotent or the snapshot was applied with the wrong environment value | Re-run the migration from a service configured with the current `DATABASE_URL`; preserve its output before retrying. | ## Related documentation - [Environment Variables](/docs/configuration/environment-variables) — scope the connection string so runtime, not build plumbing, carries the secret. - [Storage and Release Artifacts](/docs/storage) — how immutable artifacts and durable rows separate. - [Logs](/docs/operations/logs) — reading per-deployment output when a migration or connect step fails. - [Deployments](/docs/deployments) — observing which `DATABASE_URL`-configured release actually ran. --- # WordPress > Launch a managed WordPress site with private MySQL and persistent site content. Source: https://nexthomelabs.com/docs/services/wordpress Markdown: https://nexthomelabs.com/docs-md/services/wordpress Slug: services/wordpress Section: Create Keywords: wordpress, mysql, cms, themes, plugins, persistent content Last updated: 2026-09-03 Reading time: 3 min read Headings: ## What NexHost creates | ## First launch | ## What is deliberately not promised yet | ## Operations | ## Troubleshooting | ## Related documentation --- # WordPress Choose **WordPress** when you want NexHost to run the WordPress application for you. The service creates a public WordPress container, a private MySQL database, and persistent storage for `wp-content`. Uploads, themes, and plugins therefore remain when the WordPress container is replaced during a restart or deployment. ## What NexHost creates - A maintained WordPress Apache image with automatic listener discovery and isolated public ingress. - A dedicated MySQL database on the service's private workspace network. - Generated database credentials and WordPress security keys. These values are encrypted by the control plane and are not displayed in deployment logs. - A persistent Docker volume mounted at `wp-content` for customer-managed uploads, themes, and plugins. NexHost assigns the external route. There is no customer-facing port field and no user-configured health-check URL: the worker confirms that the container has opened a reachable TCP listener before the release is activated. ## First launch 1. In **New Project**, choose **WordPress**. 2. Give the site a stable name and choose the region and instance profile. 3. Review the managed MySQL and persistent content settings, then deploy. 4. Open the generated platform URL and complete WordPress's first-run administrator setup. 5. Attach a verified custom domain from the service's Domains settings when the site is ready. The first browser visit completes WordPress's normal installer. Keep the administrator account and password in your own password manager; NexHost does not create or retain the WordPress administrator password. ## What is deliberately not promised yet This first managed WordPress service does **not** include automatic WordPress updates, scheduled database backups, staging environments, multisite management, or a NexHost plugin-management console. Configure WordPress, themes, and plugins through its administrator interface, and make an external, verified backup before any destructive content or database operation. ## Operations - **Restarting WordPress** recreates the application container with the same private database and persistent `wp-content` storage. - **Suspending the service** stops the WordPress and MySQL containers while retaining their managed volumes for recovery. - **Deleting the service** removes its containers. Treat deletion as destructive and ensure you have a verified backup of any content you must keep. ## Troubleshooting | Symptom | Likely cause | Fix | | --- | --- | --- | | Deployment stops before WordPress starts | The selected worker cannot pull the maintained WordPress or MySQL image, or MySQL did not become ready | Open the deployment log and retry after the worker's network/image issue is resolved. Credentials are kept out of the log. | | WordPress cannot reach the database | The managed MySQL container is stopped or its initial bootstrap failed | Restart the WordPress service. NexHost verifies and starts the managed MySQL resource before starting WordPress. | | Uploads or themes are missing | The files were stored outside `wp-content`, or a previous deployment was created before persistent content storage was available | Store mutable WordPress files in `wp-content` and restore any needed content from a verified backup. | ## Related documentation - [Custom Domains](/docs/configuration/custom-domains) — connect a production hostname after domain verification. - [Deployments](/docs/deployments) — follow the managed provision log and release status. - [Logs](/docs/operations/logs) — understand customer-safe deployment output. --- # Workflows > Run an on-demand container task with run history, timeouts, and bounded retries. Source: https://nexthomelabs.com/docs/services/workflows Markdown: https://nexthomelabs.com/docs-md/services/workflows Slug: services/workflows Section: Create Keywords: workflow, task, container, retry, timeout, on-demand Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use — and when not to | ## Configure the task | ## Review runs | ## Related documentation --- # Workflows A **Workflow** runs a container task **on demand** — not continuously like a [Background Worker](/docs/services/background-workers), and not on a fixed cron cadence like a [Cron Job](/docs/services/cron-jobs). Use it for bounded work that should have a **recorded run history**, a **timeout**, and **retry limits** instead of a permanently running process: a per-invoice render, a per-document export, a reconciliation pass, a data import that handles unexpected size by restarting rather than by staying online indefinitely. Because each invocation is an isolated container run, retrying is explicit, bounded, and inspectable — the history records the captured exit status and application text per invocation. ## When to use — and when not to **Use a Workflow when:** - The unit of work has a natural finish line — a document produced, a dataset exchanged, an entity migrated — and there are many distinct invocations rather than a persistent queue reader. - The run needs a formal **timeout** (kill the step after a wall-clock limit) and a **retry limit** (fail after N attempts) so a stuck input cannot stall the whole domain. - History matters more than availability: auditors, stakeholders, or teammates need to see "which input was processed in run #37 and how long did it take?" **Do not use a Workflow when:** - The process must **stay alive continuously** consuming from a queue or stream — use a [Background Worker](/docs/services/background-workers). - The process fires on a fixed **UTC cadence** with no per-input trigger — use a [Cron Job](/docs/services/cron-jobs). - The need is an HTTP service — use [Web Service](/docs/services/web-services). > [!INFO] > Workflows sit between a Worker and a script: they have the control surface of a deployment (image, command, environment, timeout, retry) but the execution shape of a finite task. If "running for hours until stopped" sounds correct, lean Worker; if "run once with a watch timer" sounds correct, lean Workflow. ## Configure the task Choose **Workflow**, provide the **container image and command** required for the task, then set the **task timeout** and **retry limit**. Each field has a distinct responsibility: - **Container image** — the image that contains the task program and its dependencies. This is commonly an image pushed from external CI rather than the workspace’s repository build; confirm the tag or digest is the one you intend to run. - **Command** — the invocation that defines what this workflow run *is*. For example `python scripts/render_invoice.py --id $INVOICE_ID`, `node scripts/export.js`, or a binary plus arguments. Keep the command **deterministic**: the same image plus the same command plus the same inputs should produce the same logical outcome, not timing-dependent jitter. - **Timeout** — the wall-clock limit after which the platform terminates an unresponsive run. Choose it for the worst plausible size of a healthy invocation (for example "rendering the largest invoice" or "importing the largest batch size your application allows") rather than for the average case. - **Retry limit** — the bounded number of retries after transient failures. Useful for temporary provider or network issues; harmful as a loop over bad inputs, so keep the limit small and the failure-classification inside the command honest. Keep the command **deterministic** and make it **safe to retry** where possible. An import that can safely be restarted from the last externally observable checkpoint (a remote offset, a deterministically derived partition key) is less harmful to rerun than one that duplicates side effects per retry. > [!TIP] > Encode input narrowly. A workflow task that takes an exact invoice, document, or job ID is easier to rerun and retry than one that implicitly scans an unbounded range. Prefer `workflow --id=123` over "workflow scans for all pending jobs" when per-entity history matters. ## Review runs The **workflow screen records each invocation and its outcome** — whether it succeeded, timed out, or hit the retry ceiling — with the exit status and application output captured per run. **Inspect a failed run before retrying** so a configuration or input problem is not repeated automatically. What to look for when the last run failed: - **Exit status** — non-zero signals "the task reported failure," not "the platform did." Distinguish a deterministic bug in the input (which should be fixed before any retry) from transient infrastructure or provider throttling (where a retry may genuinely help). - **Application output** — the task’s own stdout/stderr plus the platform’s bookkeeping. The first error line in the earliest anomalous span is usually the root cause — later retries and wrapper timeout logs are often consequences. - **Timeout vs crash** — a timeout implies the task kept running but never completed within the limit; a crash often appears as an immediate non-zero exit with a short duration. Fix them differently: a timeout wants a longer timeout or a leaner input partitioning; a crash wants a code or environment repair. > [!WARNING] > Do not blindly retry a failed run with invalid input. A retry storm over a malformed document accumulates the recorded retry budget while producing only repeated failures. ## Related documentation - [Background Workers](/docs/services/background-workers) — continuous consumers with a "stay alive" model rather than per-run history. - [Cron Jobs](/docs/services/cron-jobs) — scheduled, clock-driven finite runs in UTC where the cadence is the trigger, not the demand. - [Logs](/docs/operations/logs) — reading application output and stage information for a task that does not serve HTTP. - [Deployments](/docs/deployments) — observing the lineage of the workflow’s configuration alongside domain runs. - [Services Overview](/docs/services) — placing Workflows among the other service types before committing to the model. --- # 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 Keywords: environment variables, configuration, secrets, build, runtime, port Last updated: 2026-08-30 Reading time: 6 min read Headings: ## When to use this | ## Scopes | ## Set a value | ## Keep secrets server-side | ## Runtime port | ## Troubleshooting | ## Related documentation --- # 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`. --- # Custom Domains > Attach a domain to a public NexHost service and complete the dashboard-guided DNS verification. Source: https://nexthomelabs.com/docs/configuration/custom-domains Markdown: https://nexthomelabs.com/docs-md/configuration/custom-domains Slug: configuration/custom-domains Section: Configure Keywords: custom domain, dns, tls, ssl, domain verification, hostname Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use this | ## Before you begin | ## Add the domain | ## How ownership, routing, and TLS relate | ## Common issues | ## Propagation and operational tips | ## Related documentation --- # Custom Domains Add a custom domain from the project’s domain settings **after a public service has a successful release**. The dashboard then shows the exact DNS records required for the selected domain and a live verification status — ownership, routing, and certificate — so you know which step is blocking. A custom domain is a property of the hostname, not the source code. You can attach or detach it without redeploying the service; verification is about DNS proof, not about what the application does at runtime. ## When to use this Use this flow when the generated workspace hostname (for example `…nexthost.example`) is no longer the public address you want to share — when launching, when a customer-facing domain must read as `www.example.com`, or when email senders need to authenticate against your own domain. Do not start here if the public service has never succeeded; verify that the release is healthy first and then attach the domain. ## Before you begin - At least one **public** service (Static Site, Frontend App, or Web Service) with a **successful release** — the domain flow attaches to a deployed service. - Access to the **DNS provider** for the domain so you can create TXT/CNAME/A/AAAA records as shown by the dashboard. Read-only access is not enough. - A few minutes of patience. DNS edits can take time to propagate, and verification retries on its own schedule. ## Add the domain 1. Open **Dashboard → Domains** or the project’s domain settings. 2. Enter the hostname you want to use, such as `www.example.com` or `api.example.com`. Use the full hostname you plan to serve — do not add an apex without reading the dashboard note about apex handling first. 3. Choose the available DNS management option shown for that domain. 4. Copy the **ownership** and **routing** records shown by the dashboard into your DNS provider **exactly as displayed** for the domain you are adding. 5. Run verification after the records have propagated. The domain detail screen reports each check independently. Do not guess record names or targets from another project — even one inside the same workspace. The values displayed for **the domain you are adding** are authoritative and can differ between domains and between attachment attempts. Copying a stale record from history or from a different domain is the most common reason for "it looks correct but stays pending." > [!WARNING] > Create records only for the integer domain row you just added. Deleting or editing unrelated records in a zone is out of scope for this flow and can break other services. ## How ownership, routing, and TLS relate The three verifications are sequential: ownership and routing must both succeed before the certificate step can complete. | Step | What the dashboard checks | What to do when it is pending | | --- | --- | --- | | **Ownership** | A TXT or equivalent record that proves you control the domain | Compare the displayed host, value, and quoting against the provider. Watch for trailing dots, quoting, or whitespace added by the DNS UI. | | **Routing** | The host record that points traffic at the NexHost target shown for this domain | Confirm the host matches the target shown **for this domain**, not a nearby project or a previous record. | | **Certificate (TLS)** | Certificate issuance for that hostname | Complete ownership and routing verification first, then check the domain screen for its current status. Leave ownership/routing records in place after verification — they are not throw-away tokens. | NexHost manages certificate issuance for verified hostnames. Leave the verification records in place unless the domain screen tells you otherwise — removing them too early causes verification to drop and the certificate not to renew. ## Common issues | Status | What to check | Common false fix | | --- | --- | --- | | **Ownership pending** | The ownership record exactly matches the dashboard value at the authoritative DNS, has propagated, and has not been truncated or reformatted by the provider’s UI. | Changing unrelated records or adding the same value twice in a different label. | | **Routing pending** | The host record matches the target shown **for this domain** right now — not for another domain, project, or previous attempt. | Reusing a routing value from screenshot history rather than from the current domain row. | | **Certificate pending** | Complete ownership and routing verification first, then check the domain screen for its current status. Certificates cannot be issued for hostnames that are still unverified. | Repeatedly clicking verification without addressing the earlier failing check. | If a record looks correct but verification remains pending, give propagation a few minutes and retry verification. Use the dashboard’s support path and include **the domain and displayed status** — never post DNS credentials, API tokens, or service secrets. Including a screenshot of the domain row with secrets redacted is more useful than a TXT of raw zone dumps. ## Propagation and operational tips - Use the DNS provider’s **preview** or **dig**-equivalent view to confirm the authoritative answer before you conclude that "the provider says it is done." Many UIs show queued edits as if they were live. - TTL matters. A long TTL on a previous conflicting record can delay the appearance of the new value at resolvers the verifier queries. - If you manage multiple hostnames (`www.example.com` + `example.com` or `app.example.com` + `api.example.com`), attach and verify each independently — they have distinct record sets and statuses. - Do not share DNS provider credentials outside a private, access-controlled credential store. ## Related documentation - [Domains and Networking](/docs/configuration/networking) — public vs private access models and how `PORT` and health paths interact with hostnames. - [Logs](/docs/operations/logs) — reading stage output when a release never became reachable enough for domain attachment. - [Workspaces and Access](/docs/teams) — who can add domains and how workspace access is scoped. --- # Domains and Networking > Understand public and private service access before connecting applications. Source: https://nexthomelabs.com/docs/configuration/networking Markdown: https://nexthomelabs.com/docs-md/configuration/networking Slug: configuration/networking Section: Configure Keywords: networking, public service, private service, domain, port, TCP readiness Last updated: 2026-08-30 Reading time: 4 min read Headings: ## Why the split exists | ## Public access | ## Private access | ## TCP readiness | ## Choosing between public types | ## Related documentation --- # Domains and Networking NexHost separates **public services** from **internal workspace services** at the service-type boundary. The type you choose at creation determines which access model applies, how hostnames are provisioned, and which configuration knobs exist. Understanding that split before you wire applications together prevents the most common connectivity mistakes: trying to reach a private service from the public internet, or exposing an internal worker on a URL that the internet can fetch. ## Why the split exists Public services are internet-reachable. NexHost provisions a managed hostname, handles inbound HTTP routing, and supports an optional custom domain after your first successful release. Private services and Postgres are reachable only from other services in the same workspace — they are intentionally not on the public internet so internal traffic can stay scoped and least-privileged without extra firewalling on your side. ## Public access Static Sites, Frontend Apps, and Web Services receive a **public hostname after a successful release**. Before that release there is no URL to browse — the hostname is a property of the release, not the service declaration. - After a successful release the dashboard displays the generated hostname for that service. Open it to confirm the service is responding. - You can add a **custom domain** through the dashboard once the service is ready; see [Custom Domains](/docs/configuration/custom-domains). - Public runtime services (Frontend Apps and Web Services) run behind automatic TCP listener discovery and isolated Docker ingress. Static Sites have no process and do not need readiness detection. What NexHost handles versus what you handle: | Concern | Responsibility | | --- | --- | | External HTTPS and hostname allocation | NexHost handles. Do not front the generated hostname with another reverse proxy unless you intend to operate routing yourself. | | Process binding inside the service | Your application must bind to `0.0.0.0`. NexHost supplies `PORT=3000` as a compatibility default and discovers the listener it actually opens. Binding only to `127.0.0.1` makes the process unreachable. | | External port and readiness URL | NexHost handles both. It assigns a unique host port behind the public route and verifies TCP reachability; no customer health path is required. | > [!INFO] > A fixed internal port such as `3000` or `8080` is safe: every service runs in its own container network namespace. NexHost assigns the external host port and public route. ## Private access Private Services and Postgres are intended for use **inside the workspace network**. Use the connection details displayed in the dashboard from other workspace services. The dashboard is authoritative here — hostnames, ports, connection strings, and internal URLs shown there are the correct values for the current release of that service. Guidelines for private wiring: - Treat the **workspace** as the network boundary. An internal service in workspace A is not reachable from workspace B, even if both are yours. - Read connection information from the **private service or database detail screen**, not from another service’s logs or from memory of a previous release. Values can change between releases. - Do not use a Private Service where users or third-party clients need a public URL. If callers are on the public internet, ship a public runtime instead and enforce application-level authentication. ## TCP readiness NexHost waits for the application to open a reachable TCP listener during startup. It does not fetch an application URL or require a `/health` route. Keep a health endpoint if it is useful to your own monitoring, but deployment readiness depends on the process remaining alive, completing initialization, and binding to `0.0.0.0`. ## Choosing between public types The three public host types are distinct products, not aliases for the same runtime: - Use [Frontend App](/docs/services/frontend-app) for a **server-rendered UI** — Next.js server rendering, Nuxt server output, Remix, SvelteKit with a server adapter, and similar stacks. - Use [Web Service](/docs/services/web-services) for an **API or general backend** — Express, Fastify, Koa, Django, Flask/FastAPI, Go, and other persistent servers that answer API callers. - Use [Static Site](/docs/services/static-sites) for **pre-built files with no server process** — hand-written HTML, Vite/React `dist`, Astro `dist`, Next.js with `output: "export"` publishing `out`, or SvelteKit’s static adapter producing `build`. > [!TIP] > When in doubt between Frontend App and Web Service, ask where the primary user interaction is. If the product *is* the UI, choose Frontend App. If the product *serves* an API to many clients and the UI is elsewhere, choose Web Service. ## Related documentation - [Custom Domains](/docs/configuration/custom-domains) — attach a real hostname after the first successful public release. - [Environment Variables](/docs/configuration/environment-variables) — how `PORT` reaches your process, and how other secrets are scoped. - [Deployments](/docs/deployments) / [Deployment Troubleshooting](/docs/deployments/troubleshooting) — reading stage output when startup readiness or binding fails. --- # Deployments > Follow a NexHost release from source preparation through build, startup, and readiness. Source: https://nexthomelabs.com/docs/deployments Markdown: https://nexthomelabs.com/docs-md/deployments Slug: deployments Section: Operate Keywords: deployments, releases, build logs, TCP readiness, restore, deployment history Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use this | ## Release flow | ## How to use the deployment list | ## Review a deployment | ## Restore a release | ## Building confidence over time | ## Next steps --- # Deployments Every deployment records five things: **which source** brought the code, **which configuration** was in force, **what the build output** said, **whether the platform could start the artifact**, and the **final status**. Open **Deployments** from the dashboard to see releases across the whole workspace, or use a single project’s deployment history to watch one service in isolation. Treat deployments as the platform’s audit log for itself. When someone asks what shipped, what failed, and what changed, the deployment detail page is the answer. ## When to use this - When you want to know whether a change you made actually reached production. - When a build succeeded locally but the remote release failed or never became reachable. - When you need to restore a previously known-good release quickly. ## Release flow Each release moves through a fixed sequence. The detail page separates output by stage so you can tell whether the problem was source, configuration, or application behavior: 1. **Source** — NexHost prepares the selected repository, archive, folder, or image. Failures here usually mean the branch, path, or image reference did not resolve. 2. **Dependencies and build** — the configured install and build commands run when required (`npm ci`, `pip install -r requirements.txt`, `npm run build`, etc.). Failures here mirror the same commands failing locally. 3. **Publish or start** — a Static Site publishes its output directory; a runtime service starts its configured process (for example `npm start`, `gunicorn …`, or a custom server command). 4. **Readiness** — runtime services must open a TCP listener reachable through their container network. NexHost discovers that listener and allocates isolated ingress automatically; Static Sites skip this step. The release detail page shows **which step failed** — not just that something failed. A successful build followed by a failed readiness check is a startup/configuration issue, not a source-build issue. That distinction decides whether you touch source/settings or application startup and binding behavior next. > [!TIP] > The split exists so you fix in the right layer. A successful build that cannot become reachable will not be fixed by changing the branch — read the startup and readiness output instead. ## How to use the deployment list The workspace **Deployments** screen is a live, filtered view over all recent releases. Use it as a system dashboard; drill into a project’s own **Deployments** tab when you care about a single service. | What you want | Where to click | What to notice | | --- | --- | --- | | "Did my last commit deploy?" | Sort by time, find the row for the service and branch | Source commit or archive name, status, and timestamp. | | "Which configuration rode with that release?" | Open the row → detail page | Framework detection where available, output directory, chosen stack, and scoped environment variables snapshot. | | "Why is the public URL still serving the previous version?" | Status column: look for a failed readiness step | A healthy build but failed startup readiness leaves the previous successful release live. | | "Who triggered what?" | Detail line for trigger/source + timestamp | The actor and the recorded source line — useful when multiple teammates deploy. | ## Review a deployment Open a deployment to review its **source information**, **framework detection** where available, **output directory**, **build log**, and **timestamps**. Some useful checks in order: 1. **Source** — branch and root directory match the package that actually contains the build manifest? A mis-pointed root is a frequent source of dependency failures. 2. **Framework / stack** — does the detected stack match the actual project? When the dashboard suggests a different preset, correct it rather than carrying a stale assumption forward. 3. **Configuration snapshot** — build and start commands, publish directory, and environment variable scoping all ride with the release record. If two otherwise-identical deploys behave differently, the diff of this snapshot is often the explanation. 4. **Build log** — search from the first error upward. The earliest error is usually the root cause; later timeouts and connection warnings are downstream consequences. 5. **Timestamps** — correlate the deployment time against when a teammate says they pushed or changed a setting. Use **Retry deployment** only **after** correcting the relevant source or configuration problem. Retrying the same failing input with no change produces the same failure and buries the useful log diff under noise. ## Restore a release When the project shows a **previous successful release**, use the **restore action on that release** to make it active again. Restoration does not rebuild — it returns the project to a previously observed working state, which is valuable when a recent change was clearly harmful. Before you confirm, review the restore summary — the platform shows the service and the version you are about to reactivate. Confirm you are restoring the right project and the right release (timestamp and source line), then confirm the action. Not every project will have a previous successful release available; when none is shown, restore is not applicable. > [!WARNING] > Restoration brings the platform back to a release the platform previously recorded as successful — it does not merge, patch, or cherry-pick a single file. Fix forward in Git/CLI and redeploy if a surgical change is more appropriate. ## Building confidence over time Two habits keep the deployment history useful rather than noisy: - **Small, diagnosable changes.** Prefer one edit per release while debugging. Changing two things at once doubles the search space when you compare two logs. - **Own the review screen.** Before clicking deploy, re-read the branch, root, commands, directory, and environment variable scopes with the detail page of the **next** deployment in mind — as if you will soon need to read it cold. ## Next steps - Something failed in an identifiable stage? Start at [Deployment Troubleshooting](/docs/deployments/troubleshooting) — it maps symptoms to stage and exact field to check. - Need broader reading of output? See [Logs](/docs/operations/logs) for how the detail page is structured and how to share excerpts safely. - Deploying a frontend that still fails startup readiness? Reread [Frontend Apps](/docs/services/frontend-app) and verify the start command and `0.0.0.0` binding pattern shown there. --- # Deployment Troubleshooting > Diagnose source, build, startup, and TCP-readiness failures from the deployment detail page. Source: https://nexthomelabs.com/docs/deployments/troubleshooting Markdown: https://nexthomelabs.com/docs-md/deployments/troubleshooting Slug: deployments/troubleshooting Section: Operate Keywords: troubleshooting, build failure, TCP readiness, port, deployment, debugging Last updated: 2026-08-30 Reading time: 6 min read Headings: ## How to read a failure | ## Source and build failures | ## Startup and TCP-readiness failures | ## Make one correction at a time | ## Related documentation --- # Deployment Troubleshooting Start with the exact stage and message shown on the deployment detail page. The most useful first distinction is whether the release failed while preparing or building source, or after the application actually started. Those two families of failures have completely different fixes: one is about project and dashboard configuration, the other is about application runtime behavior. Use this page as a checklist rather than prose to skim. Match the symptom you see to the stage noted on the detail page, apply the listed check, redeploy once, and compare the new log to the previous one. ## How to read a failure The deployment detail page separates a release into stages for exactly this diagnosis: - **Source → Dependencies → Build** — did we correctly locate, install, and compile the code? - **Publish or start → TCP readiness** — did the artifact produce the expected output, did the process launch, and did a container-network listener become reachable before the startup deadline? A successful build followed by failed TCP readiness is a startup/configuration issue, not a source-build issue. Treating them the same slows down debugging because the two phases are fixed in different places (source/settings versus code and runtime contract). > [!TIP] > Read stage output **from the first error upward**. Later warnings and timeouts are usually consequences of the earliest failure, not fresh root causes. ## Source and build failures These are dash-before-code failures: the code might be perfectly correct, but the platform never got to start it because the chosen source, directory, or build command did not reproduce what builds locally. | Symptom | What it means | Check | | --- | --- | --- | | Dependency installation fails | The workspace install could not reproduce the local state | Lockfile, package manager selection, and the configured **root directory**. Does `npm ci` / `pip install -r requirements.txt` pass locally in the same directory you pointed NexHost at? | | Build command fails | The production build itself errored | Run the **same** production build locally (`npm run build`, `pip install …`, `go build`, etc.) and compare the command with the service configuration character-by-character. A missing env value at build time is a common hidden variant — scope the variable correctly (see [Environment Variables](/docs/configuration/environment-variables)). | | Static output is not found | NexHost built successfully but could not publish | Confirm the **publish directory** contains the generated `index.html` and assets after a local build. A common pair of mistakes is `dist` vs `out`, or pointing at the repository root instead of the package subdirectory in a monorepo. | | Wrong service type | A static build was uploaded as if it were a server (or vice versa) | Use Static Site only for exported files (`dist`, `out`, `build`); use [Frontend App](/docs/services/frontend-app) or [Web Service](/docs/services/web-services) for a server build. Uploading `.next` to a Static Site is not supported. | | Framework-detection warnings | The dashboard’s suggestion does not match the actual layout | Review the **root directory** and the detected framework; correct it explicitly rather than accepting a stale preset from a different project. | Typical multi-step fix for a build failure: 1. Re-run the exact build command locally in a clean checkout — not in a long-lived local branch where caches hide the issue. 2. Confirm the publish directory listing (`ls dist`, `ls out`, `ls build`) contains `index.html`. 3. Mirror those values — branch, root directory, build command, publish directory, scoped environment variables — into the service configuration. 4. Deploy one corrected attempt and read the new stage output against the previous one. ## Startup and TCP-readiness failures These are after-code failures: the source was prepared and built, and the platform attempted to start the process, but the runtime could not reach a TCP listener. | Symptom | What it means | Check | | --- | --- | --- | | **Startup readiness timed out** | The process did not open a reachable listener before the startup window ended | The **start command** launches a **persistent** process and the process reaches its server listen call. A bare `npm run build` as a start command starts nothing and will always time out. | | **Connection refused** | The process is running but its listener cannot be reached through the container network | Bind to **`0.0.0.0`**, not only `127.0.0.1`. `process.env.PORT` is supplied as a compatibility default, but a fixed internal port such as `3000` is also safe because NexHost discovers it. | | **Next.js static deployment fails** | The app needs a server but was shipped as static files | If the project does **not** use `output: "export"`, it must not be a Static Site. Create a [Frontend App](/docs/services/frontend-app) instead and ship source — not `.next` or `out`. | | **Startup readiness intermittent / flaky** | The service sometimes opens a listener before the deadline and sometimes does not | Move slow work out of the critical startup path and investigate dependency connections that can block initialization. | Minimal reproduction when startup readiness blocks you: ```bash # Reproduce locally with the same values the dashboard shows PORT=3000 npm start # confirm the process has opened a listener locally ss -lnt | grep ':3000' ``` If the process does not open a listener locally, NexHost cannot route it either. ## Make one correction at a time Update the source or configuration, then start a new deployment. Compare the new log with the previous one instead of changing several settings at once. If the same failure persists, collect the deployment URL, stage, and relevant log lines for support — remove secrets before sharing any output. Why one change at a time matters: most deployment failures have two or three nearby causes (for example a wrong publish directory *and* a missing build variable). Fixing both in one edit hides which assumption was wrong; fixing them sequentially teaches you which had signal. The deployment history keeps every attempt, so the diff between two small edits is the precise diagnosis. When filing a report with your team or support, include: - The project and service name as shown in the dashboard. - The deployment URL (the detail page, not a screenshot of its header alone). - The failing stage name and a short excerpt of the surrounding log — with passwords, tokens, connection strings, and private hostnames redacted. ## Related documentation - [Logs](/docs/operations/logs) — how to locate and read every stage’s output without leaking secrets. - [Deployments](/docs/deployments) — the full release flow and how to restore a previous successful release. - [Environment Variables](/docs/configuration/environment-variables) — build vs runtime scope so values arrive in the right phase. - [Frontend Apps](/docs/services/frontend-app) / [Web Services](/docs/services/web-services) — runtime contracts for listener binding and startup. --- # Logs > Use deployment build output and service details to investigate a NexHost release. Source: https://nexthomelabs.com/docs/operations/logs Markdown: https://nexthomelabs.com/docs-md/operations/logs Slug: operations/logs Section: Operate Keywords: logs, build logs, deployment details, troubleshooting, release stages Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to open logs | ## Find the relevant release | ## What the stages mean | ## Reading output like a diff | ## Share logs safely | ## Related documentation --- # Logs The deployment detail page is the primary place to inspect release output on NexHost. Every release records the **source-preparation**, **dependency**, **build**, and **release** stages, plus TCP-readiness observations when the service runs a server. There is no separate "download the full raw log forever" artifact to chase — the detail page is where the platform accumulates the truth of that attempt. Understanding the shape of this output makes debugging faster and keeps you from rediscovering the same cause across multiple releases. ## When to open logs Reach for deployment logs when: - A build passed locally but the remote release failed on the same branch. - The platform accepted the source but startup readiness timed out. - You need to answer "what actually shipped, when, with which settings" for review or on-call triage. If the issue does not involve a deployment (for example a domain-ownership check or a workspace-permission question), the deployment log is unlikely to add signal — prefer the settings screen and its status display for that domain. ## Find the relevant release The workspace has a cross-project **Deployments** screen, and each **project has its own deployment history**. Use them in combination: the workspace view is a live system dashboard, and the per-project history isolates one service. 1. Open **Deployments** in the dashboard. 2. Filter or open the project’s deployment history. 3. Select the release whose status needs investigation — match the **timestamp, status, and source commit or archive name** rather than assuming the first row is your attempt. 4. Read the output **from the first error upward**; later messages often follow from the original failure and will misdirect you if you scan bottom-up. > [!TIP] > Match the exact release rather than skimming the top row. When two teammates deploy concurrently, the release you care about may be one line down. The commit hash or archive filename is the precise identifier — not the human-readable summary alone. ## What the stages mean The detail page splits every release into stages. The ordering is not cosmetic: it mirrors the sequence in which the platform actually performed the work. | Stage | What the platform did | Typical problems at this stage | What to try next | | --- | --- | --- | --- | | **Source** | Resolved the selected repository/archive/folder/image, checked out the chosen branch, and scoped to the root directory | Incorrect repository, archive file, branch, or root directory; image reference that does not resolve | Confirm the branch exists, the root points at the directory that contains the build manifest (`package.json`, `requirements.txt`, `go.mod`, etc.), and the source is the one you intended. | | **Dependencies** | Installed language dependencies (`npm ci`, `pip install -r requirements.txt`, etc.) | Missing lockfile, package not found, network restriction, wrong package-manager selection | Run the **identical** install command locally in a clean checkout of that branch and directory; compare. | | **Build** | Ran the configured build command | Compilation error, framework configuration error, missing environment value needed at build time, failing tests gated into the build step | Run the same production build locally and compare character-by-character with the service’s build command; verify variables scoped to Build/Both where the framework needs them at compile time. | | **Publish or startup** | Static Sites publish the output directory; runtime services start the configured process | Missing static output (`index.html` not found in the publish directory), invalid start command, application that exits immediately | For static: `ls` the local build output and confirm the publish directory (`dist`, `out`, `build`, `.`). For runtime: run the same **start command** locally and confirm it stays alive. | | **TCP readiness** | (Runtime services) Detected a listener and verified that it is reachable through the container network | The application did not open a port, bound only to `127.0.0.1`, or is blocked during initialization | Confirm `listen(port, "0.0.0.0")`; `process.env.PORT` defaults to `3000`, but a fixed internal port is also discoverable. | > [!INFO] > Client-side build values (`NEXT_PUBLIC_*`, `VITE_*`) are intentionally inlined into the artifact during the **Build** stage. An expired key is not a runtime secret rotation — it is a new deployment where the build re-inlines the new value. ## Reading output like a diff Two releases that differ by only one setting are dramatically easier to diagnose than two releases where several things changed at once. When debugging: 1. Make **one** change between attempts (a different publish directory, a corrected branch, an additional environment variable). 2. Re-run the deployment and read the new log against the previous one. The line that changed is where the diagnosis lives. 3. When the same stage fails identically across two corrected attempts, widen the hypothesis rather than retrying blindly. ## Share logs safely The raw deployment detail already contains everything an on-call engineer needs except access to the platform. When you share it, share precisely and without secrets. Before sharing output with another person — whether a teammate, a public forum, or support — **remove**: - Passwords, access tokens, connection strings, and private URLs - Internal hostnames or IP addresses that are not yours to disclose - Full workspace credentials or provider API keys The dashboard output is most useful for support when paired with: - The **project name** and **service name** as shown in the dashboard (not a screenshot of just the header). - The **deployment time** or **deployment URL** (the detail page URL itself). - The **failed stage** name and the first few lines around the earliest error. > [!WARNING] > Never paste real secrets into chat, logs, screenshots, or issue trackers. Redact values and keep key names so reviewers can reason about configuration without seeing the value. ## Related documentation - [Deployments](/docs/deployments) — the full release flow, retry semantics, and restoring a previous successful release. - [Deployment Troubleshooting](/docs/deployments/troubleshooting) — symptom tables that descend from exactly the stages described here. - [Environment Variables](/docs/configuration/environment-variables) — when a build-time vs runtime variable explains a missing value. - [Frontend Apps](/docs/services/frontend-app) / [Web Services](/docs/services/web-services) — runtime contracts for listener binding and startup that determine the final stage. --- # Storage and Release Artifacts > Understand the difference between immutable deployment artifacts and application data. Source: https://nexthomelabs.com/docs/storage Markdown: https://nexthomelabs.com/docs-md/storage Slug: storage Section: Create Keywords: storage, artifacts, releases, persistence, data, immutability Last updated: 2026-08-30 Reading time: 5 min read Headings: ## The two layers | ## Release artifacts | ### What happens between two releases | ## Application data | ## Secrets and uploads | ## Related documentation --- # Storage and Release Artifacts Each successful build produces the **artifact** used for that release — a deployment output, not the project source. Release artifacts are **managed by NexHost** and are separate from the source archive or repository you uploaded. That separation is deliberate: source keeps intent ("what the team wrote"), artifact keeps what actually ran ("what the platform built and served or started"). Understanding which layer is mutable and which is immutable prevents two common errors: editing a previous artifact as if it were a file store, and treating a deployment release as a database. ## The two layers | Layer | What lives there | Mutable? | When it changes | | --- | --- | --- | --- | | **Source** | Repositories, ZIP archives, local folders, or container image references you select on creation | You control it — push, re-upload, or re-reference. | When you change code and select it as the deployment’s source. | | **Artifact** | The built output: the published static directory for a Static Site, or the captured build + launch configuration for a runtime service | **Immutable** — a successful release’s artifact is not retroactively patched | When a deployment runs and the build/start steps produce a new recorded artifact. | | **Application data** | The durable, long-lived state your users create — rows in Postgres, files intentionally stored behind an application API, uploaded media where you decided how to persist it | Managed by you — via the data services the application talks to | Continuously, under the traffic your service serves. | > [!INFO] > There is a third layer only for private context: **deployment build output** (the logs) is also a retained, immutable record per deployment. It is useful for diagnosis but is not application data. ## Release artifacts Static Sites publish the **configured output directory** (for example `dist`, `out`, or `build`). Runtime services (Frontend Apps, Web Services, Private Services, Background Workers, Cron Jobs) use the **prepared build and startup configuration** for their release — install command, build command, start command, root directory, and environment variable snapshot as recorded at deployment time. Treat artifacts as **deployment outputs**: - Make source changes in your **repository or archive**, then create a **new release** rather than editing a previous artifact. Patching an artifact would invalidate the history that lets you compare two deployments and rewind when needed. - Do not rely on the local filesystem of a deployment as durable storage. A future deployment can re-provision, a scale event can re-place the workload, and an artifact is replaced — not merged — by the next successful release. - Review the deployment detail page after each release to confirm the artifact you expected was produced: the published directory listing for a static site, or the captured build/start capture for a runtime. ### What happens between two releases A new deployment re-runs the build (when the service requires one) and re-records a new artifact. Previous artifacts remain in history so you can compare or restore. Overwriting the source in Git is not overwriting the artifact — the platform keeps both layers’ provenance distinct. ## Application data Do not rely on a deployment artifact as **mutable application storage**. An upload directory placed inside a runtime image or inside a static output folder is not durable: the next deployment can replace it, and uploading directly onto an artifact without an application-owned path is a pattern the platform cannot guard for you. Store durable relational data in [Postgres](/docs/services/postgres) or use the data service appropriate to the application — a database the platform manages, or an external store you integrate with. Keep backups and data-retention decisions **under your team’s control**, not as an accident of which file happened to persist between two releases. Good planning habits before shipping: - Decide whether the feature needs **row data** (relational — favorite Postgres candidate), **blob storage** (large objects where the dashboard does not offer a blessed store), or **no persistence** (ephemeral preview data). - Wire the **connection string or provider credentials** to the application service as scoped environment variables, not as checked-in configuration. - Record your **backup and retention expectations** alongside the service configuration — so on-call knows whether "rollback to yesterday’s artifact" should also restore a database. ## Secrets and uploads Keep secrets in [Environment Variables](/docs/configuration/environment-variables), not in source or release files. A `.env` committed to a repository is permanently in history even after you rotate the value; a dashboard-scoped environment variable is not. The same principle applies to user input: treat user-provided content as **data**, not as code to commit. For user uploads and generated media, decide **how they will be stored before deployment**. Depending on your needs, that path may be a database row, a provider bucket behind an integration call, or opaque storage in an external system. A deployment release can change independently of that application data — uploads that happen after the previous release are not "lost because of the next deploy" unless the application rolled its own naive filesystem store into the artifact. Decide that path explicitly, because moving it after users rely on it is disruptive. > [!WARNING] > Avoid committing or layering secrets into images and artifacts. The layer history preserves them. Rotate a credential the moment you suspect it was ever captured into an artifact or log — do not wait to "check later." ## Related documentation - [Postgres](/docs/services/postgres) — the managed database to pair with runtime services when durable relational data is needed. - [Environment Variables](/docs/configuration/environment-variables) — keep credentials out of source and scope them to Build/Runtime/Both. - [Deployments](/docs/deployments) — how releases and their artifacts evolve and how restoration works. - [Logs](/docs/operations/logs) — reading artifact-linked output without leaking secrets. --- # NextStorage Object Storage > Buckets, API keys, uploads, object URLs, and usage for NextStorage on NexHost. Source: https://nexthomelabs.com/docs/storage/nextstorage Markdown: https://nexthomelabs.com/docs-md/storage/nextstorage Slug: storage/nextstorage Section: Create Keywords: nextstorage, storage, buckets, objects, api keys, uploads Last updated: 2026-09-14 Reading time: 6 min read Headings: ## What is NextStorage | ## Creating a Bucket | ## Endpoint | ## API Authentication | ## Generating an API Key | ## Uploading Objects | ## Object Keys | ## Listing Objects | ## Retrieving Objects | ## Public Buckets | ## Private Buckets | ## Videos and large files | ## Deleting Objects | ## Usage and Limits | ## Errors --- # NextStorage Object Storage NextStorage is Nexthomelabs' fourth product alongside NexHost, ProperInbox, and Nextsend: S3-style object storage for applications. Create buckets in the dashboard, generate a NextStorage API key, upload files through the NextStorage API, and serve them from your `nexthomelabs.net` object URLs. Every workspace starts with a 10 GB free quota. ## What is NextStorage NextStorage gives every workspace: - **Buckets** — logical containers similar to R2 or S3 buckets. - **Objects** — files addressed by a path-like object key and a unique object UID. - **API keys** — `nhs_live_…` credentials for programmatic uploads. - **Object URLs** — `https://storage.nexthomelabs.net/o/:objectUid` delivery addresses. - **Usage** — stored bytes, bandwidth, requests, and object counts. ## Creating a Bucket 1. Open **NextStorage** in the dashboard. 2. Choose **Create Bucket**. 3. Enter a bucket name and choose **Private** (default) or **Public**. 4. Open the bucket to upload objects, browse by prefix, or change settings. Buckets are isolated by workspace. Another workspace cannot list, read, or write your buckets. Deleting a non-empty bucket requires explicit confirmation. ## Endpoint The canonical Storage API lives on the dedicated storage host with no backend prefix: ```text https://storage.nexthomelabs.net/v1 ``` Object delivery uses the same host (`/o/:objectUid` and `/b/:bucketUid/:objectKey`). The older `nexthomelabs.net/api/storage/v1` and `nexthomelabs.net/storage/...` paths keep working for backward compatibility. ## API Authentication Every programmatic request uses a workspace API key: ```http Authorization: Bearer nhs_live_xxxxxxxxxxxxxxxxxxxxx ``` ## Generating an API Key 1. Open **NextStorage**, then **API Access**. 2. Enter a key name and choose permissions. 3. Choose **Generate key**. 4. Copy the full key immediately — it is shown only once. Available permissions: - `storage:read` - `storage:write` - `storage:delete` - `buckets:read` - `buckets:write` Revoke a key at any time. Revoked keys stop working immediately. ## Uploading Objects ```bash curl -X POST "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects" \ -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY" \ -F "file=@./photo.jpg" \ -F "key=images/photo.jpg" \ -F "visibility=public" ``` JavaScript: ```js const form = new FormData(); form.append('file', file); form.append('key', 'products/gown.jpg'); form.append('visibility', 'public'); const response = await fetch('https://storage.nexthomelabs.net/v1/buckets/my-assets/objects', { method: 'POST', headers: { Authorization: 'Bearer nhs_live_CUSTOMER_API_KEY' }, body: form }); const object = await response.json(); console.log(object.url); ``` A successful upload returns: ```json { "id": "obj_01K5DV7AXY0G6PPDX9M66ACZXQ", "bucket": "my-assets", "key": "products/gown.jpg", "name": "gown.jpg", "contentType": "image/jpeg", "size": 428193, "visibility": "public", "status": "available", "url": "https://storage.nexthomelabs.net/o/obj_01K5DV7AXY0G6PPDX9M66ACZXQ" } ``` ## Object Keys Object keys are path-like names: - `photo.jpg` - `avatars/user-48/avatar.png` - `products/gowns/gown-001.jpg` - `videos/promos/september.mp4` - `documents/contracts/agreement.pdf` Keys support nested prefixes, unicode filenames, and folder-style listing with `?prefix=images/&search=photo`. Path traversal (`..`, empty segments) is rejected. The object UID is independent from the object key. ## Listing Objects ```bash curl "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects?prefix=images/&limit=100" \ -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY" ``` ## Retrieving Objects Every object has a stable UID URL: ```text https://storage.nexthomelabs.net/o/:objectUid ``` Bucket-style URLs use the globally unique bucket ID returned by the API: ```text https://storage.nexthomelabs.net/b/:bucketUid/:objectKey ``` Clients stay on `nexthomelabs.net`. Delivery streams the object with the correct `Content-Type`, supports video range requests, and records bandwidth. Public images carry `ETag`/`Last-Modified` with browser and edge caching, so repeat `` loads resolve to a fast `304` instead of a full download. ## Public Buckets A public bucket is a bucket-wide grant: every current and future object can be opened through its NextStorage URL without authentication. Use this for a dedicated website-assets bucket where all files are intended for public delivery. If the bucket is private, individual objects can still be made public from the **Objects** tab or through the API. This is the safer choice when only selected images, videos, or documents should be public. ```bash curl -X PATCH "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects/images/photo.jpg" \ -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"visibility":"public"}' ``` Public URLs are delivery URLs, not API-only URLs. They return the real file with its stored `Content-Type`, so a public image can be used directly in frontend markup: ```html Product photo ``` Do not place a NextStorage API key in browser code. Public delivery requires no key and includes cross-origin headers for websites and apps on other domains. ## Private Buckets Private buckets are the default. A private object requires one of: 1. **A logged-in workspace session** — open the same-origin URL (`/api/storage/o/:uid`) in a browser signed into the owning workspace. The dashboard preview does exactly this, so a private image in a private bucket renders for members with bucket access and for nobody else. 2. **A signed URL** — mint `GET /storage/objects/:uid/signed-url` while logged in, then embed the returned `?expires&sig` URL in an `` on any site. It is bound to that team, object, and expiry (default 15 minutes, max 24 hours) and needs no session or API key to render. 3. **A NextStorage API key** with `storage:read` scoped to the team/bucket (`Authorization: Bearer nhs_live_…`). ```bash curl "https://nexthomelabs.com/api/storage/objects/obj_01K5DV7AXY0G6PPDX9M66ACZXQ/signed-url" \ -H "Cookie: nexhost_session=YOUR_SESSION" # {"url":"https://storage.nexthomelabs.net/o/obj_…?expires=…&sig=…","expiresAt":"…"} ``` ```html Private product photo ``` Making a public bucket private locks every object in that bucket. Selected objects can then be published again individually. Unauthenticated requests to private objects receive a branded private file page during browser navigation and a machine-readable `FORBIDDEN` response for API requests. ## Videos and large files Every video container is accepted (`mp4`, `mov`, `webm`, `mkv`, `avi`, and the rest) and single files may use the full 10 GB quota. Uploads are quota-gated, not format-gated: a 5 GB video succeeds while free quota remains and counts toward the 10 GB that unlocks paid storage. Keep the browser tab open until progress reaches 100% — large uploads stream to disk on the server and forward with an extended upstream timeout. Two upload paths, different ceilings: - **Dashboard browser upload** (same-origin `/api/storage/...`) crosses the CDN and tops out around 95 MB per file. Fine for images and short clips. - **Storage-host upload** (`https://storage.nexthomelabs.net/v1/...` with a NextStorage API key) bypasses that CDN cap, so multi-GB videos succeed: ```bash curl -X POST "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects" \ -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY" \ -F "file=@./big-video.mkv" \ -F "key=videos/big-video.mkv" -F "visibility=private" ``` Chunked/resumable browser uploads for multi-GB files are planned next; until then the API path above is the supported route for anything over ~95 MB. ## Deleting Objects ```bash curl -X DELETE "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects/images%2Fphoto.jpg" \ -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY" ``` Encode `/` in object keys as `%2F` when calling key-addressed routes. Deletion updates bucket usage immediately. ## Usage and Limits The dashboard shows buckets, objects, storage used, bandwidth used, and request counts. Uploads check workspace quota before contacting storage, and oversized uploads are rejected with `STORAGE_QUOTA_EXCEEDED` or `UPLOAD_FAILED`. The free tier is 10 GB per workspace with up to 25 buckets; single objects may be up to 10 GB. ## Errors NextStorage returns its own error codes: | Code | Meaning | | --- | --- | | `INVALID_API_KEY` | The supplied NextStorage API key is invalid. | | `BUCKET_NOT_FOUND` | The requested NextStorage bucket was not found. | | `OBJECT_NOT_FOUND` | The requested NextStorage object was not found. | | `STORAGE_QUOTA_EXCEEDED` | Your NextStorage storage quota has been exceeded. | | `UPLOAD_FAILED` | NextStorage could not complete the upload. | | `STORAGE_UNAVAILABLE` | NextStorage is temporarily unable to access this object. | --- # Workspaces and Access > Keep project ownership, access, and support information organized within a NexHost workspace. Source: https://nexthomelabs.com/docs/teams Markdown: https://nexthomelabs.com/docs-md/teams Slug: teams Section: Teams and Billing Keywords: workspace, team, access, projects, billing, support Last updated: 2026-08-30 Reading time: 3 min read Headings: ## How workspaces organize the platform | ## Practical access hygiene | ## Day-to-day collaboration flow | ## Getting help | ### Related documentation --- # Workspaces and Access Projects, services, repositories, domains, and billing are organized in a **NexHost workspace**. The workspace is the security and billing boundary: choosing the wrong active workspace before creating a project or changing a domain means the new resource is not visible to the intended team, and its cost rolls up to a different account. Confirm the active workspace before creating a project or changing a domain so the new resource is visible to the intended team. ## How workspaces organize the platform A workspace scopes everything a team ships together: - **Projects and services** — a project groups one or more services; services are the deployable units within it. - **Repositories** — NexHost Git repositories are owned by a workspace. - **Domains** — a custom domain attachment belongs to a workspace and is bound to a public service inside it. - **Billing** — charges, invoices, and payment contact are tracked per workspace. That scoping has operational value beyond ownership: the deployment history for a workspace answers "what shipped across our services today?" and a per-project history answers "what shipped for this specific service?" Because logs, hostnames, and environment variable snapshots are all per-release artifacts inside that boundary, the workspace is the natural place to start any audit. ## Practical access hygiene These four habits prevent the majority of access-related surprises: - **Keep project ownership and billing contact information current** in workspace settings. An owner that has left the organization should not remain the sole contact on a billing-impacting workspace. - **Use a dedicated project or service for each independently deployable application.** Sharing a single service definition across two unrelated applications makes configuration and rollback unpredictable — a change to one drifts the other without a clear history. - **Review deployment history before restoring a release.** The history lists source, configuration, and timestamp per release; it is faster to confirm the exact release you mean to reactivate than to fix the wrong restore. - **Remove credentials from source and deployment logs before sharing them** with collaborators or support. The deployment detail already contains enough for diagnosis — the project name, service name, and timestamp — without an API key being pasted alongside it. > [!TIP] > When two teams share a workspace, give each service a stable, descriptive name (`storefront-web`, `storefront-worker`, `billing-cron`) so the deployment dashboard is legible during incidents without requiring extra labeling conventions. ## Day-to-day collaboration flow - **Before you create:** confirm the active workspace name in the header. - **Before you change a domain:** open the domain row for the target workspace — domains in another workspace are not available to attach to this project. - **Before you share a log:** redact `DATABASE_URL`, passwords, tokens, and private host references. Keep only the key names where a reviewer needs to reason about configuration. ## Getting help Use **Documentation** from the dashboard navigation for product guidance and **Support** for an account or deployment issue. The fastest path to a useful response is a tight report: - The **project name**, **service name**, and **deployment time** (or the deployment detail URL) when the issue is about a deployment failure. - A short excerpt around the **first error** — not a long dump of the whole tail — with secrets already removed. - The workspace name when the issue is about ownership or visibility. Do not include **passwords, access tokens, or database credentials** — not in a support message, not in a shared log — even when they feel necessary to "show the full context." A support engineer can map from key name + stage to the fix without seeing the value. ### Related documentation - [Billing](/docs/billing) — the per-workspace billing screen and the help path inside it. - [Deployments](/docs/deployments) — reading workspace-wide vs per-project history. - [Logs](/docs/operations/logs) — sharing stage output safely. - [NexHost Git](/docs/git) — how repository visibility and ownership interact with a workspace. --- # Billing > Review workspace billing information and complete payment actions from the NexHost dashboard. Source: https://nexthomelabs.com/docs/billing Markdown: https://nexthomelabs.com/docs-md/billing Slug: billing Section: Teams and Billing Keywords: billing, invoices, payment, workspace, plan Last updated: 2026-08-30 Reading time: 4 min read Headings: ## When to review this page | ## Before changing billing details | ## How billing relates to services | ## Need help? | ## Related documentation --- # Billing Open **Dashboard → Billing** to review the billing information associated with the **active workspace**. Every charge, plan selection, and payment record is scoped to the workspace — switching workspaces changes which billing view you are inspecting just as it changes which projects and services are listed. Use the values and actions presented there as the current source of truth for plan, payment, and account details rather than relying on memory of what was chosen during setup. This page intentionally avoids repeating numeric pricing or plan limits that are better sourced from the billing screen itself. What follows is the operational workflow around billing, so charges do not surprise you and support requests do not need to ask for the same context twice. ## When to review this page - When a deployment or scaling choice you are about to make has cost implications and you want to know what the workspace already holds. - When a billing contact changes roles and the owner listed on the workspace should be updated before the next cycle. - When a payment method needs review and you want the change to route to the intended workspace. ## Before changing billing details Confirm that you are in the **correct workspace** and that the **billing contact** is current. Two small confirmations prevent most "why did the wrong account get charged" tickets: 1. Read the workspace name shown in the header. 2. Read the contact email shown on the billing screen itself. Keep payment information inside the **secure dashboard flow**. The billing screen is the only channel that should see full payment input. Do not send card details, account credentials, or transaction references through project logs, deployment detail output, or support messages unless the support channel explicitly requests a safe method — and even then, use only the channel support provides, not a general email or chat transcript. If your organization separates concerns, assign one owner to per-workspace billing contact per workspace and document that ownership outside the platform so on-call can reach the right person during a payment incident without re-discovering the assignment under pressure. > [!WARNING] > Screenshots of the billing screen that include a complete card number, expiry, or CVV must never be shared. Redact sensitive fields before saving such a capture anywhere. ## How billing relates to services Creating, resizing, or deploying services — adding a database, adding a domain, adding concurrent workers — may change the workspace bill. The billing screen reflects the active **plan** and **payment** state that corresponds to those services. Consult it before and after a meaningful service change rather than assuming a previously quoted total still applies after the workspace has grown. ## Need help? Use the **dashboard’s Support entry** for a billing question and include the **workspace name** and any **non-sensitive reference** shown in the billing view (invoice number, line item name, or date). Support can then map your message to the right record without you exposing payment data. Good first messages include: - The exact workspace name as displayed at the top of the dashboard. - The invoice number or date when the question is about a specific charge. - The service or domain name when the question is "did this service cause this line item." Avoid: - Pasting card numbers, account logins, or transaction secrets into logs, tickets, screenshots, or chat messages. - Sharing the same message across workspaces when they have different owners — route the message to the accounting owner for the workspace that owns the charge. The dashboard Support path is the place to ask for a receipt reissue, a contact update, or a charge explanation. For non-billing operational issues, use the guidance under [Workspaces and Access](/docs/teams) and [Deployments](/docs/deployments). ## Related documentation - [Workspaces and Access](/docs/teams) — who can affect what within a workspace and how to report clearly. - [Services Overview](/docs/services) — which service types were added that may affect the bill. - [Custom Domains](/docs/configuration/custom-domains) — domain add-on state that may appear in add-on lines. --- # Next CLI > Use the NexHost Git command-line interface to work with hosted repositories. Source: https://nexthomelabs.com/docs/cli Markdown: https://nexthomelabs.com/docs-md/cli Slug: cli Section: Operate Keywords: next cli, nexhost cli, git, repositories, source control, login, doctor Last updated: 2026-08-30 Reading time: 6 min read Headings: ## What the CLI is — and is not | ## Install | ## Sign in and work with a repository | ## Available commands | ## Common workflows | ## Troubleshooting | ## Related documentation --- # Next CLI The Next CLI is NexHost’s hosted Git command-line interface. Repository access for a NexHost workspace is managed through the **Next CLI** and the dashboard’s Repositories surface; after authentication the CLI delegates source-control operations to the standard Git workflow — `add`, `commit`, `push`, `pull` — rather than introducing a second mental model for "how Git works." It is intentionally scoped: the CLI **manages repository authentication and delegates source-control operations to the standard Git workflow**. It does **not** trigger deployments, stream service logs, or set deployment environment variables — those remain dashboard operations, reviewed and triggered on the service itself. ## What the CLI is — and is not | The CLI handles | You do in the dashboard | | --- | --- | | Authenticating a workspace session for Git | Triggering or reviewing deployments | | Listing and creating hosted repositories | Reading per-deployment build output and release stages | | Cloning, committing, pushing, pulling, and syncing | Setting environment variables and health paths | | Diagnosing local Git and auth setup via `doctor` | Wiring a repository to a service source | Understanding this boundary keeps the repository change ("I pushed new code") and the release decision ("I told NexHost to deploy it") distinct — a push does not by itself change a live release. ## Install Download the current package from [CLI Downloads](/cli/downloads). On Debian or Ubuntu, install the downloaded package with: ```bash sudo apt install ./next-cli_0.1.0_all.deb ``` That `.deb` lands the platform binaries on the `PATH`. Other download formats for different operating systems are listed on the same downloads page when available. The platform command names are `next`, `nexhost`, and `nex` — all aliases for the same binary. `next` is the first-class source-control command. Before you alias or adopt it, run `which -a next` (or `where next` on Windows tooling) and confirm you do **not** overwrite an existing `next` binary from a local framework installation without checking your local environment. A Next.js project invoked via `next` on a developer machine conflicts is unwelcome; the error or wrong code path can be hard to trace if you inadvertently shadow it. > [!TIP] > Prefer to run `next --version` and `next doctor` immediately after install. A clean `doctor` output on a fresh workspace proves path, credential helper, and Git wiring before you involve real source. ## Sign in and work with a repository The typical flow is login, inspect repositories, clone one, edit, commit, and push — identical to any Git host after the first command: ```bash next login --team YOUR_WORKSPACE next repo list next clone YOUR_WORKSPACE/YOUR_REPOSITORY cd YOUR_REPOSITORY next status next add . next commit -m "Initial commit" next push ``` Each step in detail: 1. **`next login --team YOUR_WORKSPACE`** — authenticates your local session to the workspace you intend to operate in. Prefer this form when you are at your own workstation. 2. **`next repo list`** — lists repositories the authenticated principal can see in that workspace. This confirms scope before you clone. 3. **`next clone YOUR_WORKSPACE/YOUR_REPOSITORY`** (and `next init` for a new local directory you want to turn into a hosted repository) — materializes the workspace-hosted remote into a local Git directory with a credential-safe remote URL. 4. **`next status`, `add`, `commit`, `push`, `pull`, `sync`** — operate on the checked-out branch. Authentication is preserved by the CLI across these commands; the remote URL itself does not expose the credential. You can also use these authentication variants when the situation calls for them: - `next login --device --team YOUR_WORKSPACE` — **device flow** for browsers or constrained terminals. The CLI prints a code and flow URI; authorize in the browser that *is* authenticated to the workspace. - `next login --pat` — **personal access token** flow. Enter a token via the secure prompt — do not paste a token into shell history or draft messages where it may linger in logs. Rotate tokens that were ever echoed or typed in plain view. > [!WARNING] > Never embed a PAT or session credential in a remote URL and never commit a token to the repository. NexHost’s credential handling is designed to keep the remote URL credential-free — `next doctor` will confirm it. ## Available commands | Command | Purpose | Typical next step | | --- | --- | --- | | `login`, `logout`, `whoami` | Manage the current hosted-Git session: authenticate, end the session, or confirm who you are | After `login`, `next repo list`; after `logout`, `next login --team …` before you clone | | `repo list`, `repo create` | View or create hosted repositories in the workspace (`repo create` can carry `--private` to set visibility) | `next clone YOUR_WORKSPACE/` or `next doctor` when the local wiring needs checking | | `init`, `clone` | Start or retrieve a repository — `init` to wire a fresh local directory, `clone` to fetch an existing one | `next status`, then the `add → commit → push` cycle | | `status`, `add`, `commit`, `push`, `pull`, `sync` | Run familiar source-control operations through Git plumbing with the workspace session applied | Push to publish, `pull`/`sync` to incorporate teammates’ changes before branching | | `doctor` | Check the local CLI and Git setup — credential helper, PATH, Git versioning | Run whenever auth fails or a clone/pull reports credential or remote problems | After you push source, **connect that repository to a NexHost service in the dashboard** to create a deployment. During **New Project**, choose the source that corresponds to your hosted repository, pick the branch, confirm the root directory, and review build and start settings. The Git push produced the artifact source; only the dashboard action turns it into a recorded release. ## Common workflows **Create, push, and wire:** ```bash next login --team YOUR_WORKSPACE next repo create my-service --private next clone YOUR_WORKSPACE/my-service cd my-service # edit, test locally next add . next commit -m "Ship the service" next push # Dashboard → New Project → choose NexHost Git → pick my-service + branch → set build/start → Deploy ``` **Doctor and repair:** ```bash next doctor # credential helper & Git wiring next whoami # confirm session identity next logout next login --team YOUR_WORKSPACE ``` ## Troubleshooting | Symptom | Likely cause | Fix | | --- | --- | --- | | `not logged in` / auth on clone | Session expired, wrong `--team`, or unauthenticated terminal | `next whoami`, then `next login --team YOUR_WORKSPACE` or `next login --device --team …` on headless sessions | | `remote: access denied` | Repository exists in a different workspace or visibility is wrong | Verify the `YOUR_WORKSPACE/REPOSITORY` label in the dashboard Repositories screen matches what you typed | | `command not found: next` shadows Next.js | PATH ordering or shadow of the framework binary | Check `which -a next`; invoke the platform binary via its full name (`nexhost`) or a shell that disambiguates | ## Related documentation - [NexHost Git](/docs/git) — the hosted repository side: dashboard creation, push semantics, and connecting to a service. - [API Access and Availability](/docs/api) — what is not a public programmatic surface and the support path for integrations. - [Your First Deployment](/docs/getting-started/your-first-deployment) — numbered dashboard path from source to verified URL. --- # NexHost Git > Create, clone, and connect a NexHost-hosted Git repository to a service. Source: https://nexthomelabs.com/docs/git Markdown: https://nexthomelabs.com/docs-md/git Slug: git Section: Operate Keywords: git, repository, clone, push, nexhost git, branches Last updated: 2026-08-30 Reading time: 6 min read Headings: ## When to use NexHost Git vs another source | ## Create a repository | ## Push source | ## Branches, visibility, and ongoing development | ## Connect it to a service | ## Troubleshooting | ## Related documentation --- # NexHost Git NexHost Git provides **hosted repositories that can be selected as a service source**. Rather than coupling the platform to an external code host, workspaces can own repositories directly on NexHost, manage visibility there, and choose that repository as the source when they create or reconfigure a service. Repository access is managed through the dashboard and the [Next CLI](/docs/cli) — the CLI handles authentication and the Git operations; the dashboard handles wiring that repository to a deployment. The mental model is three hops: **create the repository, push source into it, connect it to a service**. A push does not by itself change a live release — deployments are created or triggered from the service in the dashboard. ## When to use NexHost Git vs another source **Choose NexHost Git when:** - You want repository ownership and deployability to live inside the workspace — useful for small teams, platform-internal services, or cases where the source does not belong on a public Git host. - You want to provision repositories from the CLI (`next repo create …`) and keep credentials out of remote URLs. **Stay with another source when:** - The source already lives in GitHub/GitLab/your organization’s preferred Git host and the team would be fragmented by duplicating it. - A public Git URL is the intended source and read-only fetch is sufficient. ## Create a repository Open **Dashboard → Repositories** and create a repository in the intended workspace. Choose its visibility and copy the clone information presented by the dashboard. The dashboard is authoritative for the workspace-qualified name (`YOUR_WORKSPACE/your-repository`) — copy it rather than reconstructing it. You can also create a repository from the CLI — this is often faster when you are provisioning several services: ```bash next login --team YOUR_WORKSPACE next repo create my-service --private ``` What that gives you: - A hosted repository named `YOUR_WORKSPACE/my-service` with the visibility flag you set (`--private` keeps it private to the workspace). - A credential-safe remote URL materializing only via the CLI checkout flow — `next clone` and the credential helper cooperate so the remote URL itself never has to contain a token. - The workspace as the ownership boundary — only principals in `YOUR_WORKSPACE` can see or push to that repository. > [!TIP] > Match the repository name to the service it will back wherever possible (`my-service` rather than `test-2026-temp`). The dashboard displays the exact repository name in the deployment detail, so readable naming reduces triage friction during incidents. ## Push source After creation, push the initial source via the CLI: ```bash next clone YOUR_WORKSPACE/my-service cd my-service next add . next commit -m "Initial service" next push ``` Each step in more detail: - **`next clone YOUR_WORKSPACE/my-service`** — clones via the platform credential helper rather than a token-bearing URL. - **`next add .` / `next commit`** — the usual Git staging/commit cycle, operating on whatever branch you are on. - **`next push`** — pushes to the hosted remote on the current branch. Private visibility stays enforced workspace-side. - **`next doctor`** — if authentication or the local Git configuration is not ready, `doctor` is the one-line health check for credential helper and Git wiring. The CLI keeps credentials out of repository remote URLs, so a `git remote -v` does not leak a session token even if you paste it in a shared doc. If you do need to share the remote instruction, share the **qualified label** (`YOUR_WORKSPACE/my-service`) rather than a computed URL. > [!WARNING] > Do not commit secrets to the hosted repository — connection strings, tokens, and private keys belong in service-scoped [Environment Variables](/docs/configuration/environment-variables). A repository commit containing a secret is still a secret in history even after you rotate it. ## Branches, visibility, and ongoing development NexHost Git repositories use **standard Git branches**. Selecting a branch for a service happens on the service itself — during **New Project** and later when you reconfigure the service to track a different branch. Typical lifecycle: 1. Create the repository with the desired visibility. 2. Push `main` (or your team’s default branch) and verify the branch appears on the repository screen. 3. Wire the service to that repository + branch in **New Project**. 4. For everyday development, push feature branches normally and let the service review a staged branch before promoting. > [!INFO] > The platform makes no assumption that `main` is the only deployable branch. Point the service at whichever branch represents the desired cut for that service; updating the branch on the service is the act of retargeting. ## Connect it to a service During **New Project**, choose **NexHost Git as the source** when it is offered, select the **repository and branch**, then review the service’s build, start, or publish settings before deploying. Pay particular attention to the *Root directory* when the repository is a monorepo — the path should point at the package that contains the build manifest (`package.json`, `requirements.txt`, `go.mod`), not at the repository root. What happens after the wiring: - A **source push** does **not by itself** change a live release. After you push fresh commits, go to the service and start or configure the deployment from the dashboard so the platform records a new release with that updated source. - The deployment detail records **which repository + branch + commit** produced each release, along with the captured build and launch settings. Future comparisons between a working and a broken release read that provenance. - Framework detection, output directory, build log, and timestamps are captured per release as well, so you can diff two releases even when Git history alone is unclear. > [!TIP] > Review the captured Git commit and root directory captured on the release detail before you assume a deployment honors the most recent push. A mis-pointed branch or an un-pushed local commit will surface there first. ## Troubleshooting | Symptom | Likely cause | Fix | | --- | --- | --- | | `not authenticated` on clone/push | No active workspace session or wrong `--team` | `next login --team YOUR_WORKSPACE` (or `--device` on headless sessions), then `next whoami` to confirm | | Repository not listed in New Project source selector | Repository is in a different workspace | Open Repositories inside the **active** workspace and verify the qualified name `YOUR_WORKSPACE/your-repo` there | | Push succeeds but release still shows old commit | Service branch points at a different branch than the push | Reopen the service, change the branch in source settings, and start a new deployment | ## Related documentation - [Next CLI](/docs/cli) — full install, auth modes, and the `doctor` health check. - [Deployments](/docs/deployments) and [Logs](/docs/operations/logs) — reading the per-release record of which source actually ran. - [Your First Deployment](/docs/getting-started/your-first-deployment) — the numbered dashboard path from source to verified hostname. --- # API Access and Availability > Understand the current supported programmatic interfaces for NexHost. Source: https://nexthomelabs.com/docs/api Markdown: https://nexthomelabs.com/docs-md/api Slug: api Section: Operate Keywords: api, cli, git, automation, programmatic access, control plane Last updated: 2026-08-30 Reading time: 4 min read Headings: ## What "no public REST API" means | ## Supported programmatic interface | ## Dashboard actions — the intended control plane | ## Building integrations when the dashboard is not enough | ## Related documentation --- # API Access and Availability NexHost is operated through the dashboard. Every authenticated request your browser makes — opening a project, reading a deployment, updating environment variables, creating a domain attachment — flows through an authenticated control plane that exists to serve **the dashboard itself**. That control plane is a product-internal interface, not a versioned, public REST API contract for general-purpose automation. That distinction matters for two reasons: a browser-bound interface that your workspace would automate against can change without the deprecation notices a public API must offer, and treating a browser session as a bearer token risk for a workspace expands the blast radius of credential exposure. The guidance below follows from that responsibility. ## What "no public REST API" means - The dashboard’s own endpoints are **authenticated control-plane endpoints for the dashboard**. They are not published as a general-purpose public REST API contract and should not be used for unsupported automation — for example by scripting a browser session credential or by scraping and calling internal URLs observed in the network panel. - The absence of a public API today does not mean that result tables, form endpoints, and internal request paths are stable integration surfaces. Relying on them risks breakage without warning and can expose the underlying account. If you are evaluating whether NexHost can be automated in a pipeline, read the next section for the stable surface that does exist and the recommended path for everything else. ## Supported programmatic interface For **hosted repository workflows** — the source layer that feeds the dashboard — use the [Next CLI](/docs/cli). It is the stable, supported programmatic interface for repository operations over an authenticated NexHost Git surface: - **Session and identity:** `next login` (with `--team`, `--device`, or `--pat`), `next logout`, `next whoami` - **Repository lifecycle:** `next repo list`, `next repo create my-service --private` - **Clone and initialization:** `next init`, `next clone YOUR_WORKSPACE/YOUR_REPOSITORY` - **Source control:** `next status`, `next add .`, `next commit -m "…"`, `next push`, `next pull`, `next sync` - **Diagnostics:** `next doctor` The CLI handles repository authentication and keeps credentials out of remote URLs, so a typical workflow is: ```bash next login --team YOUR_WORKSPACE next repo list next clone YOUR_WORKSPACE/YOUR_REPOSITORY cd YOUR_REPOSITORY # edit, test locally next add . next commit -m "Ship the API" next push # then, separately, create or reconfigure the service deployment in the dashboard ``` Pushing source does not by itself trigger a deployment — the dashboard is the control plane for services. The source change is the artifact the next deployment will reference, not the trigger. > [!INFO] > The Next CLI manages repository authentication and delegates source-control operations to the standard Git workflow. It does **not** trigger deployments, stream service logs, or set deployment environment variables — those remain dashboard operations. ## Dashboard actions — the intended control plane Create and manage **services, deployments, domains, and billing** through the dashboard. Every action you need to evaluate access to — who can read a deployment log, who can rotate a secret, who can attach a custom domain — is authored there, and the set of controls your workspace sees is shown there. The exact actions available to a workspace are the ones presented in the current dashboard and can evolve as the product matures. Treat the dashboard’s affordances as the design surface: if a workflow is absent from the dashboard and from the CLI’s documented repository operations, assume it has no supported programmatic surface yet. ## Building integrations when the dashboard is not enough If you need an integration that cannot be completed in the dashboard or through the Git CLI — for example a custom release gate, a deployment notification that does not exist in the current UI, or a workspace-provisioning operation — **contact NexHost support with the workflow you need** rather than automating against browser endpoints. What to include when you write in: - The **workspace name**, which service type and source the service uses, and the step you want to perform. - What trigger you want (every push, a filtered push, a manual gate) and who should be able to invoke it. - Where the result should go — a channel, a deployment policy, an access change — rather than how you envision the HTTP call would look. Support can advise on what is actually available, what is planned, and a safe integration shape that will not break silently when the dashboard evolves. > [!WARNING] > Do not embed browser session credentials in scripts, do not commit tokens to repositories, and do not rely on undocumented dashboard URLs. That pattern can break without notice, bypasses the intended access controls, and may expose account access to anyone who obtains the script or its history. ## Related documentation - [Next CLI](/docs/cli) — install, authentication modes, and the full repository workflow. - [NexHost Git](/docs/git) — hosted repositories and the push → dashboard-connect → deploy sequence. - [Workspaces and Access](/docs/teams) — how workspace scope relates to who can perform dashboard actions. - [Deployments](/docs/deployments) — the intended deployment lifecycle without leaning on unsupported endpoints. --- # Node.js Quickstart > Deploy a small Node.js HTTP application as a NexHost Web Service. Source: https://nexthomelabs.com/docs/quickstarts/node Markdown: https://nexthomelabs.com/docs-md/quickstarts/node Slug: quickstarts/node Section: Quickstarts Keywords: node.js, express, web service, port, TCP readiness, quickstart Last updated: 2026-08-30 Reading time: 4 min read Headings: ## When to use this quickstart | ## Before you begin | ## Create the application | ## Configure the service | ## What success looks like | ## Troubleshooting | ## Related documentation --- # Node.js Quickstart This quickstart deploys a small HTTP application as a [Web Service](/docs/services/web-services). NexHost discovers its reachable TCP listener and assigns ingress automatically, so the application must start a persistent server bound to `0.0.0.0`. Use [Frontend App](/docs/services/frontend-app) instead for a server-rendered Next.js, Nuxt, Remix, or SvelteKit UI. The contract is the same — start a server bound to `0.0.0.0` — but the frontend service exists so your UI and backend can have separate hostnames and build/start semantics while both using the public-runtime model. ## When to use this quickstart **Use this page when:** - The deliverable is a public Node backend — Express, Fastify, Koa, NestJS, or a lightweight `http` server — that should answer browser, mobile, and webhook callers over a hostname. - You want a five-minute sanity check that your application’s startup shape is correct before you connect a larger repository. **Skip this quickstart when:** - The deliverable is a server-rendered frontend — use the [Frontend App](/docs/services/frontend-app) flow, where `next start -p $PORT` is the launchable. - The deliverable is pre-built static files only — use [Static Site](/docs/services/static-sites). ## Before you begin - Node.js 18+ locally (for local verification). - A NexHost workspace and permission to create a project. - A few minutes on the command line — the guide intentionally avoids tooling magic so the dashboard values match what you just typed. ## Create the application From an empty parent directory: ```bash mkdir my-node-app && cd my-node-app npm init -y npm install express ``` Create `index.js` at the project root: ```js const express = require("express"); const app = express(); const port = Number(process.env.PORT); app.get("/", (_request, response) => response.send("Hello from NexHost")); app.get("/health", (_request, response) => response.status(200).json({ ok: true })); app.listen(port, "0.0.0.0", () => { console.log(`Listening on ${port}`); }); ``` Why this shape: - `Number(process.env.PORT)` reads NexHost's compatibility default (`3000`). A fixed internal port is also safe because NexHost discovers the listener and assigns the external port. - Binding to `"0.0.0.0"` attaches to the container’s network interface, not only to loopback. Binding only to `"127.0.0.1"` makes the runtime observe "connection refused" even when your localhost `curl` succeeded. - `/health` is optional application monitoring; NexHost readiness is based on TCP reachability rather than this route. Set the start script in `package.json`: ```json { "scripts": { "start": "node index.js" } } ``` > [!TIP] > Verify locally before you deploy: > > ```bash > PORT=3000 npm start & > curl -i http://127.0.0.1:3000/health > # expect 200 with {"ok": true} quickly, no authentication required > ``` ## Configure the service 1. In **New Project**, select **Web Service** — not Frontend App, not Static Site. 2. Choose a supported source and connect this project — a repository checkout, ZIP archive, or local folder. Confirm the branch and root directory when offered. 3. Set **Start command** to `npm start`. The dashboard already knows the install and build commands needed for most Node projects; if you customized them locally, mirror those values here. 4. Deploy and open the generated hostname shown by the dashboard after the release becomes ready. The server must bind to `0.0.0.0`. It may use `process.env.PORT` or a fixed internal port; NexHost discovers it automatically. > [!WARNING] > Do not place secrets in client-inlined variables for a frontend that shares this workspace. A service-scoped secret should not be given a browser-exposed prefix just because another service is a static site. ## What success looks like - The deployment detail page shows the process log line "Listening on " and a TCP-readiness confirmation. - The service’s **generated hostname** at the dashboard loads `Hello from NexHost` at `/` and `{"ok": true}` at `/health` — both without passing a cookie or header. - Future environment variable changes on this service apply at the next deployment or re-launched process, depending on whether they were scoped to Build or Runtime. ## Troubleshooting | Symptom | What to check | | --- | --- | | Startup readiness times out | Is `npm start` the start command rather than `npm run build` (which exits immediately)? Does the server bind to `0.0.0.0` and reach its listen call? | | Connection refused | Binding only to `127.0.0.1` is the classic variant. | | Build succeeds but process exits quickly | The start command built rather than ran — move the build step to Build and keep a continuous start mechanism in Start. | See [Deployment Troubleshooting](/docs/deployments/troubleshooting) for the full symptom table and [Logs](/docs/operations/logs) for reading each stage’s output. ## Related documentation - [Web Services](/docs/services/web-services) — full public-runtime contract for Node backends. - [Frontend Apps](/docs/services/frontend-app) — the analogous flow for server-rendered frontends. - [Environment Variables](/docs/configuration/environment-variables) — when to scope a key to Build vs Runtime vs Both. - [Domains and Networking](/docs/configuration/networking) — public hostnames, custom domains, and the `PORT` contract. --- # Python Quickstart > Deploy a Python HTTP application as a NexHost Web Service. Source: https://nexthomelabs.com/docs/quickstarts/python Markdown: https://nexthomelabs.com/docs-md/quickstarts/python Slug: quickstarts/python Section: Quickstarts Keywords: python, flask, fastapi, web service, port, gunicorn, uvicorn, quickstart Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use this vs a different service | ## Before you begin | ## Create a Flask application | ## Create a FastAPI variant (optional) | ## Configure the service | ## What success looks like | ## Troubleshooting | ## Related documentation --- # Python Quickstart Use a [Web Service](/docs/services/web-services) for a Python HTTP application. NexHost waits for a reachable TCP listener, so the application must start a persistent server bound to `0.0.0.0`; the platform discovers the listener and assigns ingress automatically. This guide uses Flask for the example and notes the matching FastAPI variant. The contract is the same for both: bind to `0.0.0.0` and keep the process alive. A fixed internal port is safe because containers are isolated. ## When to use this vs a different service **Use Web Service (this guide) when:** - The deliverable is an HTTP server that should answer browser, mobile, or webhook callers over a public hostname. - You need readiness gating: callers should only reach the service once it has proved it can serve requests. **Do not use Web Service when:** - The process should be reachable only from inside the workspace — choose [Private Service](/docs/services/private-services). - The process is a persistent asynchronous consumer with no HTTP — choose [Background Worker](/docs/services/background-workers). - The process should run on a schedule and exit — choose [Cron Job](/docs/services/cron-jobs). ## Before you begin - Python 3.10+ locally so you can verify the server starts and opens a listener before deploying. - A fresh directory for the project, or an existing service directory inside a monorepo. - A workspace and permission to create a project. ## Create a Flask application In an empty directory, create `app.py`: ```python import os from flask import Flask app = Flask(__name__) @app.get("/") def home(): return "Hello from NexHost" @app.get("/health") def health(): return {"ok": True} if __name__ == "__main__": # NexHost supplies PORT=3000 as a compatibility default. app.run(host="0.0.0.0", port=int(os.environ["PORT"])) ``` Why this shape works on the platform: - `os.environ["PORT"]` reads NexHost's compatibility default. A fixed internal port is also discoverable. - `host="0.0.0.0"` binds to the container interface, not only to loopback. Binding only to `127.0.0.1` makes TCP readiness observe "connection refused" even when your direct localhost test passed. - `/health` is optional application monitoring; NexHost deployment readiness is based on TCP reachability. Create `requirements.txt` in the same directory: ```text Flask gunicorn ``` `Flask` is the framework; `gunicorn` is the production WSGI server you will actually run. TCP readiness verifies that the running `gunicorn` workers opened a listener, not just that the file imports correctly. > [!TIP] > Test locally before you deploy: > > ```bash > python -m venv .venv && source .venv/bin/activate > pip install -r requirements.txt > PORT=3000 python app.py & > curl -i http://127.0.0.1:3000/health > # expect 200 with {"ok": true} quickly and without authentication > ``` ## Create a FastAPI variant (optional) If you prefer FastAPI, the same readiness contract applies — only the runner changes: ```python # app.py import os from fastapi import FastAPI app = FastAPI() @app.get("/") def home(): return {"message": "Hello from NexHost"} @app.get("/health") def health(): return {"ok": True} ``` `requirements.txt`: ```text fastapi uvicorn ``` The platform-observed difference is only the **start command**: Flask uses `gunicorn`, FastAPI uses `uvicorn`. ## Configure the service 1. Select **Web Service** in **New Project** — not Frontend App and not Private Service. 2. Connect the **repository or archive** containing `app.py` and `requirements.txt`. Verify the branch and root directory when the dashboard shows them. 3. Set **Build command** to `pip install -r requirements.txt`. If your project lives in a subdirectory of a monorepo, point the root directory there first so this path resolves. 4. Set **Start command** to `gunicorn app:app --bind 0.0.0.0:$PORT`. This keeps workers alive and routes them at the injected port. 5. Deploy. The deployment detail page will show source preparation, dependency install, build (which is this `pip install`), launch, and TCP readiness — in that order. For FastAPI, use a comparable `uvicorn` start command that sets `--host 0.0.0.0` and `--port $PORT`: ```bash uvicorn app:app --host 0.0.0.0 --port $PORT ``` The flags look slightly different (`--bind` vs `--host`/`--port`) but the meaning is identical: read the injected `PORT`, bind to the correct interface, stay alive. ## What success looks like - The deployment status becomes successful and the detail page shows a populated `PORT`-aware log line rather than a hard-coded startup announcement. - The dashboard shows a **generated hostname** for the service. Opening `https:///health` returns `{"ok": true}` quickly. Opening `https:///` returns the greeting. - A fresh deployment after updating only an environment variable produces the updated `/health` response with the new value inlined to the configuration — no code edit was required. ## Troubleshooting | Symptom | Check | | --- | --- | | Startup readiness times out | Is `gunicorn`/`uvicorn` the start command rather than `python app.py` without `gunicorn`? Does the server reach its listen call after initialization? | | Connection refused | The container bound only to `127.0.0.1`. Bind to `0.0.0.0`. | | "Module not found: app" | The service’s root directory does not contain `app.py`, or `requirements.txt` referenced the wrong package. | | Build passes but the process exits immediately | The start command built but did not keep a worker pool alive — `pip install …` belongs in Build; the `gunicorn` line belongs in Start. | See [Deployment Troubleshooting](/docs/deployments/troubleshooting) and [Logs](/docs/operations/logs) for broader diagnosis. ## Related documentation - [Web Services](/docs/services/web-services) — full public runtime contract across language stacks. - [Private Services](/docs/services/private-services) — the same Python server on the workspace-private network. - [Environment Variables](/docs/configuration/environment-variables) — scope secrets so `pip install` and `gunicorn` each see the right values. - [Domains and Networking](/docs/configuration/networking) — public vs private access. --- # Static Sites Quickstart > Deploy a Vite, React, Astro, or exported Next.js frontend as a NexHost Static Site. Source: https://nexthomelabs.com/docs/quickstarts/static-sites Markdown: https://nexthomelabs.com/docs-md/quickstarts/static-sites Slug: quickstarts/static-sites Section: Quickstarts Keywords: static site, vite, react, astro, next.js, quickstart, dist, out, build Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use this | ## Before you begin | ## Example: Vite and React | ## Configure the service | ## Other static outputs | ## Environment variables for static builds | ## Troubleshooting | ## Related documentation --- # Static Sites Quickstart Use a [Static Site](/docs/services/static-sites) when your project produces files that can be served without a running Node or application server. The platform builds the output once per deployment and uploads the resulting directory — there is no long-lived process to keep alive and no health check to keep passing. This quickstart covers the two things that actually cause static deployments to fail: running the wrong build command, and publishing the wrong directory. ## When to use this Use this flow when: - The deliverable is pre-built HTML, CSS, JS, and assets — hand-written HTML, a Vite/React build, an Astro static build, or a Next.js project configured with `output: "export"`. - Every page can be generated at build time. If any page needs server rendering, middleware, or API routes at request time, use [Frontend App](/docs/services/frontend-app) instead. ## Before you begin - Node.js installed locally so you can verify the build produces the directory you plan to publish. - A workspace and permission to create a project in the dashboard. - The project’s framework confirmed (Vite, Astro, Next.js, SvelteKit with a static adapter, plain HTML). ## Example: Vite and React From an empty parent directory, create a small Vite + React site: ```bash npm create vite@latest my-site -- --template react cd my-site npm install npm run build ``` What that last step does: the `build` script (typically `vite build`) produces the static output in `dist`. Inspect it: ```bash ls dist # index.html, assets/, etc. cat dist/index.html | head -n 5 ``` If this listing looks right locally, the identical listing on the deployment detail page should match after the dashed settings you provide. ## Configure the service 1. Select **Static Site** in **New Project**. Do not select Frontend App — a static site and a frontend runtime are distinct products even when the framework name is similar. 2. Connect a **repository, folder, or ZIP archive** as the source. Confirm the branch and root directory when the dashboard shows them. 3. Set **Build command** to `npm run build`. If your repository tracks only source, this rebuilds on the platform — which is the normal path. If the repository already contains the pre-built directory, you may leave the build command empty. 4. Set **Publish directory** to `dist` (for the Vite example). The platform uploads only this directory after the build finishes. 5. Deploy and open the generated hostname displayed by the dashboard. The site should load the built UI directly. What success looks like: the deployment detail says the publish directory was found and contained `index.html`; the generated hostname serves the page; refreshing a client-side route works when the framework’s fallback is configured (many static hosts redirect unknown paths to `index.html` — add that configuration in the framework if the UI uses client routing). ## Other static outputs The same four-field configuration (service type, build command, publish directory, environment variable scope) applies to every static framework — only the values differ. | Project | Typical build command | Publish directory | Notes | | --- | --- | --- | --- | | Vite or React (default template) | `npm run build` | `dist` | Vite writes `dist/index.html` + `dist/assets`. | | Astro (static) | `npm run build` | `dist` | Astro’s static output is `dist`. | | Next.js with `output: "export"` | `npm run build` | `out` | Only after setting `output: "export"` in `next.config.js`; without that flag the project is not static and needs a Frontend App. | | SvelteKit with static adapter | `npm run build` | `build` | Install and configure `@sveltejs/adapter-static`; then `npm run build` writes `build/index.html`. | | Plain HTML | none | `.` | Hand-written `index.html` already in the repository; no build step needed. | If the application needs a runtime server after build — server rendering, API routes, middleware, `@next/image` optimization — use [Frontend App](/docs/services/frontend-app) instead of mapping a static directory over a server build. > [!WARNING] > Do not publish `.next` from a normal Next.js project as static files. `.next` is the server build; `out` is the static export. Uploading `.next` as a Static Site produces confusing "index not found" errors. ## Environment variables for static builds Static configuration is baked into the artifact. A public API endpoint that your framework inlines at build time (for example `VITE_API_URL` for Vite or `NEXT_PUBLIC_API_URL` for Next) must be set with a **Build** scope before that build runs, and changing it requires a **new deployment** — saving without redeploying leaves the old HTML/JS live. Never store secrets in client-inlined variables; anything with a `VITE_` or `NEXT_PUBLIC_` prefix is observable in the browser bundle. ## Troubleshooting | Symptom | Likely cause | Fix | | --- | --- | --- | | "Publish directory not found" | The path does not exist at the chosen root | Run `npm run build` locally, confirm `ls ` contains `index.html`, and fix the directory in the dashboard. | | Page loads but assets return `404` | Base path or asset prefix misconfigured | Check the framework’s base/asset configuration and rebuild; confirm `assets/` is alongside `index.html` in the published directory. | | API routes / `next/image` missing | App needs a server, not static files | Recreate as [Frontend App](/docs/services/frontend-app) and ship source rather than a directory of HTML. | ## Related documentation - [Static Sites](/docs/services/static-sites) — full description of the static service contract. - [Frontend Apps](/docs/services/frontend-app) — when the app needs a running Node server. - [Deployment Troubleshooting](/docs/deployments/troubleshooting) — diagnose missing outputs vs build failures. - [Environment Variables](/docs/configuration/environment-variables) — build vs runtime scope. --- # Docker Quickstart > Deploy an existing container image as a compatible NexHost runtime service. Source: https://nexthomelabs.com/docs/quickstarts/docker Markdown: https://nexthomelabs.com/docs-md/quickstarts/docker Slug: quickstarts/docker Section: Quickstarts Keywords: docker, container image, web service, worker, quickstart, existing image Last updated: 2026-08-30 Reading time: 5 min read Headings: ## When to use this vs a repository source | ## Select the service type first | ## Before you begin | ## Configure the image | ## How NexHost treats the image at deployment time | ## Troubleshooting | ## Related documentation --- # Docker Quickstart Choose an existing container image source when you already build and publish your application image outside NexHost — for example with a CI pipeline that pushes to a registry. Image sources are available for **Web Services, Private Services, Background Workers, and Cron Jobs** — not Static Sites or Frontend Apps, which are file- and Node-build–driven rather than image-driven. This quickstart shows what the dashboard expects once you pick the image path: a reference, any required command settings, environment variables, and — for public services — a health path plus a container that listens on the injected `PORT`. ## When to use this vs a repository source **Use an existing image when:** - The build is complex (multi-stage builds, non-Node languages with compiled toolchains, reproducible base-image pinning) and already lives in CI. - You ship the same image to multiple environments and want NexHost to run exactly that digest. - The platform’s repository-based build is not a good fit for your language or tooling. **Stay with a repository or archive source when:** - The app is a standard Node/Python/Go service that the dashboard can build directly. - You want the platform-provided stack detection and simpler environment-variable scoping. ## Select the service type first The service type you pick determines networking and health checking, even when the source is an image. Choose deliberately: - **Web Service** — a public HTTP server that needs a hostname and health check. This is the only image path with a public health probe. - **Private Service** — an internal HTTP or application service that other workspace services reach privately. - **Background Worker** — a persistent process without a public URL (queue consumer, event processor). It must stay up continuously. - **Cron Job** — a command that runs on a schedule and exits, with the scheduler deciding success by exit code and reporting it in the deployment history. Static Sites publish a directory and Frontend Apps build and run Node source — neither accepts an existing container image source. ## Before you begin - An image already built and available where the dashboard can reach it. Most teams keep it in a public registry or a registry the workspace is authorized to read from. - Knowledge of what the image’s entrypoint does. If the default entrypoint already starts the server, you may not need to override the command; if it expects arguments, you will supply them in the service configuration. - For a Web Service: the container must listen on the injected `PORT` (provided at runtime) and bind to `0.0.0.0`, just like a source-built service would. ## Configure the image 1. Start **New Project** and select the appropriate runtime service — for example Web Service for a public API image, or Background Worker for a queue processor image. 2. Choose **Existing image** when it is offered as the source for the selected service type. 3. Enter the **image reference** — typically `registry/namespace/name:tag` or a digest-pinned `@sha256:…` form. Verify the tag or digest corresponds to the image you just built; a stale tag is a common reason a fresh deployment appears to have "not taken." 4. Add **command settings** when the dashboard asks for them. Some images expose the service via a default `CMD`; others require a string such as `node server.js`, `python app.py`, or a binary invocation. Match what the `Dockerfile` declared as the intended startup path. 5. Add **environment variables** in the service configuration. Secrets such as connection strings or provider tokens must ride as scoped variables, not as baked-in layers in the image. 6. For a public **Web Service**, configure an **HTTP health path** (for example `/health`) and ensure the container **listens on the injected `PORT`**. A container that listens only on `127.0.0.1` or on a hard-coded port will fail health checks even when the image is otherwise correct. 7. Deploy. Use the deployment detail page to verify that **image preparation**, **startup**, and (for public services) the **health check** all completed successfully. A minimal checklist for a Web Service container: ```text Image pull succeeds → container starts → process prints "Listening on " → GET /health returns 200 quickly without authentication ``` ## How NexHost treats the image at deployment time The deployment records preparation of the selected image, launch of the container with the environment you set in the dashboard, and — for public services — the health-check probe. That last step is where image-built services fail most often for the same reasons source-built services do: the handler is missing, it requires credentials, or the container never attached to `PORT` on `0.0.0.0`. > [!WARNING] > Do not bake secrets into the image. A layer history preserves values. Use the dashboard’s environment variable flow so they can be rotated per release without rebuilding. ## Troubleshooting | Symptom | Likely cause | Fix | | --- | --- | --- | | "Image not found" / "Pull failed" | Typo in the reference, wrong tag, private registry not accessible with current workspace authorization | Correct the reference; push the image; confirm the registry path resolves outside NexHost first (for example `docker pull `). | | Build passes but health time-out | Container does not listen on `PORT` or health path is protected/missing | Confirm binding to `0.0.0.0` on `$PORT` and `curl -i /` without credentials. | | Worker starts then exits | Start command completed rather than staying alive | Workers must run a continuous process; adjust the command to the consumer/server loop, not a one-shot script. | ## Related documentation - [Services Overview](/docs/services) — choose Web Service vs Private Service vs Worker vs Cron Job before you pick the source. - [Environment Variables](/docs/configuration/environment-variables) — scoping for the variables the image will read at runtime. - [Logs](/docs/operations/logs) and [Deployment Troubleshooting](/docs/deployments/troubleshooting) — stage-by-stage diagnosis when the image preparation or startup fails. - [Web Services](/docs/services/web-services) / [Private Services](/docs/services/private-services) / [Background Workers](/docs/services/background-workers) / [Cron Jobs](/docs/services/cron-jobs) — the full contract for each image-eligible service type. --- > End of corpus. 30 articles. Sitemap: https://nexthomelabs.com/sitemap.xml — Docs home: https://nexthomelabs.com/docs