PandaStack

PR Previews

Every pull request gets its own ephemeral PandaStack environment — built from the PR's code, served behind a stable URL, and posted as a comment on the PR. Opt-in per repo; auto-torn-down when the PR closes.

PR previews give every pull request its own live, isolated environment. Open a PR → PandaStack builds it from the PR's exact commit, deploys it to a Firecracker microVM, and comments the preview URL on the pull request. Push more commits → it rebuilds. Close or merge the PR → the environment is torn down automatically.

It's the same build pipeline as a regular App — the difference is the lifecycle is driven by the pull request, and the environment is ephemeral.

PR previews are opt-in per repository. Installing the GitHub App (for app auto-deploy) does not turn previews on — you enable them per repo from the dashboard, API, or SDK. A repo with previews off ignores pull-request events entirely.

Lifecycle

PR eventWhat happens
opened / reopenedA preview environment is provisioned from the PR's head commit and deployed. The preview URL is posted as a comment on the PR.
push (new commits)The preview rebuilds from the new commit. The same PR comment is edited in place (no comment spam).
closed / mergedThe preview environment is torn down and its sandbox freed.
@pandastack delete commentTears the preview down early, without closing the PR. The command also accepts the App's own handle — @<app-slug> delete.

The PR comment is a single sticky comment that tracks state: ⏳ Building → ✅ Ready (with the URL) → ❌ Failed if a build breaks.

Enabling previews for a repo

Previews are off by default. Turn them on for a specific repo via any of:

In the Apps page, connect your GitHub account, then open the repo picker. Each repo has a Previews toggle — click it to enable (or disable) PR previews for that repo.

# Enable
curl -X POST https://api.pandastack.ai/v1/preview-repos \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"github_repo_id": 123456789, "repo_full_name": "you/your-repo"}'

# List enabled repos
curl https://api.pandastack.ai/v1/preview-repos \
  -H "Authorization: Bearer $PANDASTACK_API_KEY"

# Disable
curl -X DELETE https://api.pandastack.ai/v1/preview-repos/123456789 \
  -H "Authorization: Bearer $PANDASTACK_API_KEY"
from pandastack import Client

client = Client()

# Enable PR previews for a repo
client.apps.enable_preview_repo(123456789, repo_full_name="you/your-repo")

# List opted-in repos
client.apps.preview_repos()

# List live preview environments
client.apps.previews()

# Disable
client.apps.disable_preview_repo(123456789)
import { Client } from "@pandastack/sdk";

const client = new Client();

// Enable PR previews for a repo
await client.apps.enablePreviewRepo(123456789, { repoFullName: "you/your-repo" });

// List opted-in repos
await client.apps.previewRepos();

// List live preview environments
await client.apps.previews();

// Disable
await client.apps.disablePreviewRepo(123456789);

The github_repo_id is GitHub's numeric repository ID (not the owner/repo string). The dashboard toggle resolves it for you; for the API/SDK you can get it from the GitHub API or the connected-repos list.

GitHub App requirements

For previews to work, the PandaStack GitHub App installed on your repo needs:

  • Webhook events: Pull requests and Issue comments.
  • Permissions: Issues: Read & write (to post the preview-URL comment on the PR).

These are in addition to the repo-content read access the App already uses for cloning.

How a preview is built

A preview reuses the standard App deploy pipeline: shallow-clone the PR's commit → detect the framework → mise install the runtime → install + build → start and health-check → serve behind a stable URL. The preview runs on the base template (2 GiB / 2 vCPU).

Each preview gets a stable URL of the form https://<id>.<your-app-suffix>/ that survives rebuilds, so the link in the PR comment stays valid as you push commits.

Cleanup and limits

  • Automatic teardown. Previews are torn down when the PR closes or merges. As a backstop, a reaper also removes previews that have had no push for 24 hours (each push resets the clock) — so an abandoned PR, or a missed close webhook, can never leak a running environment.
  • Concurrency cap. Each workspace has a limit on concurrent live previews (default 10, configurable via PANDASTACK_MAX_PREVIEWS_PER_WORKSPACE). When the cap is reached, a new PR gets a comment explaining the limit instead of an environment; closing another preview frees a slot.

Previews vs. apps

AppPR preview
LifecycleLong-lived; you manage itTied to a pull request
Created byYou (dashboard / API / SDK)A PR event (once the repo is opted in)
URLStable, permanentStable for the life of the PR
TeardownWhen you delete itOn PR close, @pandastack delete (or @<app-slug> delete), or the 24h reaper
Auto-deployOn push to the tracked branchOn every push to the PR

Previews and regular apps coexist — enabling previews on a repo doesn't affect any durable app you've deployed from the same repo.

On this page