Preview deploys — NuPaaS Docs
Deploy & projects

Preview deploys

A preview is a short-lived environment for one branch of a project. It gets its own URL, optionally its own copy of your database, and it deletes itself after a period of inactivity.

How previews are created

Previews are driven by pull requests. When your Git host delivers a pull-request webhook to NuPaaS:

ParameterTypeDescription
opened / synchronizedwebhook eventQueues a build and creates the preview environment, or updates the existing one for that branch.
closedwebhook eventDeletes the preview environment for that branch.

This works for the Gitea/Forgejo integration today, and for GitHub where that integration is connected. Webhook deliveries are authenticated with an HMAC signature, and a delivery with an invalid signature is rejected.

Creating or updating a preview also posts one comment on the pull request carrying that preview's URL, so the pull request itself is where you find the address of the preview. Pushing more commits to the same pull request updates that comment rather than adding another. Closing the pull request removes the preview and its comment together.

Each preview answers at its own host, built from the pull request number, the project slug and the organization slug: pr-{prNumber}--{projectSlug}--{orgSlug}.{BASE_DOMAIN} — for example https://pr-1--e2ecamp-preview--e2ecamp-customer.nupaas.com. It is an ordinary HTTPS URL you can open in a browser, and the certificate for the preview host is issued per preview, as part of creating it.

If you open a pull request and no preview appears, check that the project's repository webhook is registered — a preview exists only because that webhook fires.

How a preview behaves

A preview serves the build of the branch it was created for, at its own host. That host serves the preview only: it does not serve the production build, which stays at the project's production URL, so the two are separate pages you can open side by side.

A preview is temporary. It disappears when its pull request closes, or when its TTL elapses after a period without activity.

A reviewer does not need the panel to open a preview: the URL is in the comment on the pull request, and that comment keeps pointing at the current preview as the branch moves. The panel is for the project-wide list of previews and for deleting one.

Branch databases

By default, creating a preview also provisions an isolated branch database cloned from the project's PostgreSQL database, and injects its connection string into the preview environment. Deleting the preview tears the branch database down with it.

Two cases behave differently and are worth knowing:

  • If the project has no PostgreSQL database, branching is skipped and the preview is created without one.
  • Branch creation can be disabled per preview. Do this for projects whose production data should not be cloned into an ephemeral environment.

Expiry and cleanup

Each preview carries a TTL measured from its last activity. The default is 24 hours, and it can be set anywhere from 1 hour to 168 hours (7 days) — values outside that range are clamped.

A background process sweeps for expired previews roughly every five minutes and deletes them. Expiry is therefore approximate: a preview is removed shortly after its TTL elapses, not exactly on the minute.

Managing previews in the panel

Open /orgs/<org>/projects/<project>/previews to see every preview for a project — its branch, status, URL, when it was created and when it expires. Each row can be deleted, with a confirmation step.

What is not available yet

Being precise about the gaps, because they are the things people assume are there:

  • No "create preview" button. The previews page lists and deletes. Creating a preview outside the pull-request flow means calling the API directly — there is no panel control and no platform CLI subcommand for it.
  • No TTL editor. The TTL is set when the preview is created; the panel does not expose a way to extend or shorten it afterwards.

To create a preview programmatically, call the preview API with the project id and branch:

CreatePreview payload
{
  "projectId": "<projectId>",
  "branch": "feature/checkout",
  "ttlHours": 48,
  "dbBranch": false
}

ttlHours and dbBranch are optional and default to 24 and true respectively. A preview created this way has no pull request, so its number is derived from the branch name: the first number in the name, or a hash of the name when it contains none.