Skip to main content
Open a pull request and Levelrail builds its head commit, deploys it as <app>-pr-<n> on its own domain, and posts one comment on the pull request with the URL. Push again and the same preview updates. Close or merge the pull request and everything the preview created is removed, including its DNS record. This page covers the lifecycle and the safety defaults. For the git hosts that support previews and the status reporting each one gets, see Preview environments and Git integrations.

Turn it on

Connect a git source to the app, then enable previews on the app’s Previews page (or levelrail-cli apps previews enable <app>). Turn on pr-status if you want the pull request comment and commit status. Previews are off until you do both.

What a preview gets

Platform defaults come from APP_PREVIEW_MEMORY, APP_PREVIEW_CPU and APP_PREVIEW_IDLE_SLEEP_MINUTES (0 turns idle sleep off). Every one of them can be overridden per app.

Environment variables per preview

A preview inherits the app’s plain environment, minus database connection variables (see below). Use preview-only overrides and branch overrides to give a preview its own values: they are applied last, so they always win.

Database strategy

Databases declared in app.yaml with ephemeralInPreviews or isolatedInPreviews keep working as before and take precedence for multi-service previews. The name matching for none is a heuristic. If a credential has an unusual name, set it to an empty value with a preview-only override.

Lifecycle

  • Each app keeps at most the platform cap of live previews (APP_PREVIEW_ENV_MAX_PER_APP), or its own number under Previews. At the cap the oldest preview is evicted, or the new pull request is skipped, depending on the app’s policy.
  • A preview with no new pushes for the TTL (default 7 days, APP_PREVIEW_TTL, per app in hours) is removed even if the close event never arrived. Extend adds time to one preview from the Previews page or levelrail-cli previews extend <app> <pr> --hours 48.
  • Teardown removes the preview’s services, its databases, and the DNS record Levelrail created. If any step fails the row stays, marked failed with the reason, and the next teardown or sweep retries only what is left. Images and volumes are reclaimed by the normal image and orphaned volume cleanup, since the preview app no longer exists.
  • Each preview has a status (deploying, active, failed, awaiting_approval, limit_reached) and a reason, shown in the list and the pull request comment.

Feedback on the pull request

One comment per pull request is created and then edited in place: building, ready (with the URL, the commit, a link to the build logs and when the preview is cleaned up), failed (with the reason), removed. A failing build also marks the commit status failed.

Forks

A pull request from a fork never deploys on its own, and never receives the app’s environment variables, secrets or overrides. Three controls, in order of risk:
  1. Default: the pull request waits. A maintainer reviews it and approves a one-time deploy from the Previews page or levelrail-cli apps previews approve <app> <pr> --yes. The preview runs without the app’s environment.
  2. --share-secrets on approve (or the checkbox in the dialog) gives that one deploy the app’s environment, secrets and overrides.
  3. allow-forks deploys fork pull requests without approval, still without environment. fork-secrets is what lets them have it: leave it off unless every contributor is trusted.
A new push from the fork needs a new approval.

Basic auth gate

Turn on the gate to put one username and password in front of every preview of an app. The password is stored encrypted with the app’s other secrets and copied to each preview domain when it is deployed. It needs the control plane master key.

CLI

previews is the same command as apps previews. settings shows the policy, or changes it when you give flags: --max-previews, --ttl-hours, --memory, --cpu, --idle-sleep-minutes, --database none|shared|fresh|seed, --seed-database, --allow-forks, --fork-secrets, --gate --gate-username --gate-password, --allow-indexing.

API

What this does not do

Preview databases are not migrated or reset between pushes, a seed restore is not waited on before the app starts, and previews run on the same node as the control plane’s other workloads unless the app is placed elsewhere.
Last modified on October 12, 2026