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:
- Provisions or restores an instance on your configured provider.
- Bootstraps the runtime for your deployment target.
- Syncs your app files to the instance over SSH (rsync) as needed.
- Runs the deployment — the step itself differs by target (see What differs by deployment target).
- Creates or updates the PR status comment with the current state.
- 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 event | Condition | What PullPreview does |
|---|---|---|
pull_request labeled / opened / reopened | Trigger label present | Deploy (up) |
pull_request synchronize (new commits pushed to the PR) | Trigger label present | Redeploy |
pull_request unlabeled | Trigger label removed | Destroy (down) |
pull_request closed / merged | — | Destroy (down) |
schedule | — | Cleanup only — removes dangling and expired deployments |
| any | Run has no PR number | Branch cleanup (fallback) |
A few specifics worth keeping in mind:
- A
scheduleevent never deploys and does not “keep previews alive.” It only removes deployments that are dangling or past theirttl. ttlcleanup is enforced only duringscheduleruns. Expiry is computed from the PR’s GitHubupdated_attimestamp, so any update to the PR resets the clock.- Only
h(hours) andd(days) suffixes are recognized forttl, plus the special valueinfinite. See Configuration for thettlinput.
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:
deploying → deployed → error (on failure), and destroying → destroyed 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.