Levelrail
Skip to content

Preview environments per pull request ​

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 ​

PropertyDefault
Name<app>-pr-<n>
Domain<app>-pr-<n>.<apps base domain> when an apps base domain is set, otherwise pr-<n>.<app>.<primary domain>, otherwise host and port only
DNSA record is created when automatic DNS is on, and removed on teardown. A wildcard record for the base domain already covers the one-label host, so nothing is written then
Resources256Mi memory and 0.25 CPU, never more than the app itself has
IdleSleeps after 30 idle minutes and wakes on the next request
Search enginesHidden: X-Robots-Tag and a deny-all robots.txt
DatabaseNone: no database credentials reach the preview
Fork pull requestsWait for approval and get no environment variables

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 ​

StrategyWhat the preview talks to
none (default)Nothing. Variables that look like database connections (DATABASE_URL, *_DB_*, REDIS_URL, POSTGRES_* and similar) and the app's attachment variable are dropped
freshAn empty database of the same engine and version as the app's attached database, created for the preview and deleted with it
seedA new database restored from the latest succeeded backup of the named seed database, in the background. Without a backup or a restore runner the preview keeps an empty database and says so
sharedThe production database. Opt in only for read-mostly apps you trust: every preview can read and change production data

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 ​

  • Cap. 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.
  • TTL. 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.
  • Cleanup. 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.
  • State. 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 ​

levelrail-cli previews list [app] [flags]
levelrail-cli previews extend <app> <pr> [--hours 24] [flags]
levelrail-cli previews delete <app> <pr> [flags]
levelrail-cli previews settings <app> [flags]
levelrail-cli previews approve <app> <pr> --yes [--share-secrets]

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 ​

RouteDoes
GET /api/v1/apps/{name}/previewsList an app's previews
POST /api/v1/apps/{name}/previews/{number}/extendAdd hours to one preview's expiry
POST /api/v1/apps/{name}/previews/{number}/teardownRemove one preview now
POST /api/v1/apps/{name}/previews/{number}/approveDeploy a held fork pull request once (share_secrets optional)
GET, PUT /api/v1/apps/{name}/preview-policyRead or change the policy

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.

Released under the Apache 2.0 License.