How it works

The full lifecycle of a preview — from label to deploy to auto-destroy — and the GitHub event model behind it.

PullPreview runs as a GitHub Action inside your workflow. It reacts to pull request and schedule events, provisions an instance on your cloud provider, deploys your app there, and reports back into the PR. This page walks through that lifecycle end to end, the event model that drives it, how deployment differs by target, and exactly what reviewers see.

Lifecycle

When you add the trigger label (pullpreview by default) to a pull request, the workflow runs against the PR commit and PullPreview does the following:

  1. Provisions or restores an instance on your configured provider.
  2. Bootstraps the runtime for your deployment target.
  3. Syncs your app files to the instance over SSH (rsync) as needed.
  4. Runs the deployment — the step itself differs by target (see What differs by deployment target).
  5. Creates or updates the PR status comment with the current state.
  6. Writes a GitHub job summary containing the preview URL and SSH details.

Note that actions/checkout runs on the GitHub runner, not on the preview instance. The action does not check code out onto the server; it syncs the checked-out sources from the runner to the instance.

After the first deployment, the environment is kept in lockstep with the PR:

  • Pushes to the PR branch redeploy.
  • Removing the label destroys the environment.
  • Closing or merging the PR destroys the environment.
  • Scheduled runs clean up expired environments according to their ttl.

On a successful deploy, the preview URL appears in both the PR comment and the job summary, the action outputs are written, and the heartbeat logs include the preview URL, the SSH command, and the list of authorized users. On destroy, the PR comment is updated to show destroy progress and result, and the instance is terminated.

See Getting started to set this up in your repository.

Event model

PullPreview decides what to do based on the GitHub event that triggered the run and whether the trigger label is present. The mapping is:

GitHub eventConditionWhat PullPreview does
pull_request labeled / opened / reopenedTrigger label presentDeploy (up)
pull_request synchronize (new commits pushed to the PR)Trigger label presentRedeploy
pull_request unlabeledTrigger label removedDestroy (down)
pull_request closed / mergedDestroy (down)
scheduleCleanup only — removes dangling and expired deployments
anyRun has no PR numberBranch cleanup (fallback)

A few specifics worth keeping in mind:

  • A schedule event never deploys and does not “keep previews alive.” It only removes deployments that are dangling or past their ttl.
  • ttl cleanup is enforced only during schedule runs. Expiry is computed from the PR’s GitHub updated_at timestamp, so any update to the PR resets the clock.
  • Only h (hours) and d (days) suffixes are recognized for ttl, plus the special value infinite. See Configuration for the ttl input.

What differs by deployment target

The provisioning, sync, and reporting steps are the same across targets. The deployment step is where they diverge.

Compose target. PullPreview renders your Compose configuration on the runner and deploys it against the remote Docker engine using a Docker context. The containers run on the preview instance.

Helm target. PullPreview bootstraps k3s on the instance, installs a Helm release named app into a dedicated namespace, and exposes it through a PullPreview-managed Caddy Deployment.

See Deployment targets for the full comparison and configuration of each.

What reviewers see (PR comment & job summary)

PullPreview surfaces status in two places, both visible to reviewers without leaving GitHub.

PR status comment

A single marker-based comment is maintained per environment/job and updated in place as the deployment progresses. It moves through these states:

deployingdeployederror (on failure), and destroyingdestroyed on teardown.

The comment includes:

  • The latest commit.
  • The current deployment state.
  • The preview URL, or a pending/destroyed marker when there isn’t one yet.
  • A link to the job logs (when the job id is available).

Job summary

At the end of the github-sync step, PullPreview appends a summary to GITHUB_STEP_SUMMARY, visible from the workflow run UI. For a successful deploy it includes:

  • Repository, branch, and commit.
  • Status.
  • A link to the preview URL.
  • A link to the job logs.
  • SSH username, IP, and the ready-to-use SSH command.

The summary ends with “Powered by PullPreview”.

If a deploy doesn’t reach the deployed state or the URL never appears, see Troubleshooting.