Hosting core concepts
View as MarkdownVariants, deployments, async jobs, and secrets — the mental model behind the Hosting API.
Overview
This page explains the mental model behind the Hosting API. Three concepts run through all resource groups: variants, async jobs, and deployments. Understanding these makes the rest of the surface readable on first contact.
The Hosting API supports Node.js apps. Other product types will be supported in future releases.
Go to Deploy your Node.js app for a hands-on walkthrough. Go to the Hosting API reference for endpoint details.
Variants
Every hosted app needs a way to test a change without exposing it to the traffic your users are already hitting. The Hosting API solves this by giving every app two parallel runtime copies, called variants, instead of leaving you to provision and wire up separate staging and production environments yourself. Each variant has its own source, its own secrets, and its own URL; however, they belong to the same app and share the same id.
The following table describes the two variants:
| Variant | What it is | Typical use |
|---|---|---|
preview | Working copy. Receives new source uploads and secret changes. | Iteration, integration testing, staging. |
publish | Production copy. Serves live traffic. | Whatever your users actually hit. |
Uploads land on preview. Publishing promotes the current preview to publish. Only the next upload overwrites preview.
Per-variant reads differ by endpoint. GET /status returns both variants in one response with no filter parameter. GET /secrets accepts an optional variant query parameter. GET /logs accepts an optional variant query parameter (PREVIEW or PUBLISH, defaults to PREVIEW), plus optional filters for source (stream), level (severity), and since (timestamp). Secret writes take variant in the request body.
Async jobs
Operations that outlive a single request return immediately with a job or deployment record. Poll a status endpoint until they reach a terminal state.
The following diagram shows the create-app polling sequence:
Terminal states
The following table lists the terminal states for each job type and the endpoint to poll:
| Job type | Poll endpoint | Terminal states |
|---|---|---|
| Create app | GET /app-operations/{operationId} | COMPLETED (ready), FAILED |
| Source import | GET /apps/{appId}/imports/{importId} | COMPLETED, FAILED |
| Publish | GET /apps/{appId}/deployments/{deploymentId} and GET /apps/{appId}/status | Latest deployment reaches COMPLETED; then inspect variants on the status response for the affected environment |
Polling guidance
The following list provides guidance for polling async jobs:
- Interval: two to five seconds is a good starting point. Back off on longer jobs.
- Give-up window: most create and upload jobs complete in under a minute. If you're still in
pendingafter several minutes, treat it as stuck and surface an error. - Idempotency: re-polling is free. The status endpoints have no side effects.
- Idempotency-Key header: Include
Idempotency-Key: <uuid>on mutation requests (POST, PATCH) to make retries safe. If the server receives a duplicate request with the same key, it returns the original response without creating a duplicate resource.
Deployments
A deployment is a snapshot of source + config that ran (or is running). Deployments are numbered and durable. Even after publish overwrites the live one, older deployments remain listable.
The following calls create and list deployments:
POST /apps/{appId}/imports # upload zip → job → new source on preview
POST /apps/{appId}/deployments # publish preview → new deployment on publish
GET /apps/{appId}/deployments # history (paginate with limit, default 20, max 50)Runtime status (GET /apps/{appId}/status) is a separate concern from deployments — it tells you whether the variant is actually up and serving, independent of what deployment it points at.
Secrets
You configure secrets per variant using a standard RFC 6902 JSON Patch array. Pass the environment as the variant query parameter (PREVIEW or PUBLISH). Each path is /{SECRET_NAME}. A single PATCH request can add, replace, or remove secrets. The combined total must not exceed 50 operations per request. The following request body shows all three operation types in one call:
[
{ "op": "add", "path": "/STRIPE_KEY", "value": "sk_test_..." },
{ "op": "replace", "path": "/DB_URL", "value": "postgres://..." },
{ "op": "remove", "path": "/OLD_FLAG" }
]The response contains metadata only (like names and last-updated timestamps). No endpoint returns secret values, including reads. If you need to know what a secret is set to, look it up in whatever system generated it.
Putting it together
The following diagram shows the full iteration loop across variants:
Every step above is a single API call plus polling. That's the whole model.
For the end-to-end deploy walkthrough, go to Deploy your Node.js app. For endpoints, go to the Hosting API reference.
Scopes reference
Every Hosting API operation requires a specific scope on your Personal Access Token (PAT). Select only the scopes your integration needs. Narrower tokens are easier to reason about when something goes wrong.
Go to Personal Access Tokens to create or update a token.
The following table describes each scope and what it unlocks:
| Scope | What it unlocks |
|---|---|
hosting.application:read | Read application details |
hosting.application:create | Create new applications |
hosting.application:update | Update application settings |
hosting.application:delete | Delete applications |
hosting.deployment:execute | Trigger deployments and restarts |
hosting.source:read | Read source import status |
hosting.source:write | Upload or link source code |
hosting.secret:read | List application secrets |
hosting.secret:write | Create or update application secrets |
hosting.log:read | Read application logs |
hosting.domain:read | Read attached domains |
hosting.domain:write | Attach or remove domains |
hosting.subscription:read | Read subscription data |
hosting.subscription:write | Attach subscriptions to applications |
Related
Last updated on
How is this guide?