How to Clean Up Stale Preview Environments on a Schedule in GitHub Actions
Run a nightly cron that lists open PRs, compares them to live previews, and destroys any preview whose PR is gone.
Teardown-on-close can miss environments when a workflow fails. A scheduled reaper is the safety net: list open PR numbers, list live previews, and delete the difference. Add workflow_dispatch for on-demand runs.
Steps
- Trigger on
schedule(a nightly cron) plusworkflow_dispatch. - List open PR numbers via the API.
- For each live preview, destroy it if no open PR matches.
Workflow
.github/workflows/preview-reap.yml
on:
schedule:
- cron: '0 3 * * *'
workflow_dispatch:
jobs:
reap:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- env:
GH_TOKEN: ${{ github.token }}
run: |
OPEN=$(gh pr list --state open --json number --jq '.[].number')
for env in $(./list-previews.sh); do
num=${env#pr-}
echo "$OPEN" | grep -qx "$num" || ./destroy-preview.sh --name "$env"
doneGotchas
- Scheduled runs use the default branch; keep the reaper script there.
- Log what would be deleted first so a bad match cannot wipe active previews.
Related guides
How to Tear Down a Preview Environment When a PR Closes in GitHub ActionsAutomatically destroy a per-PR preview environment when the pull request is closed or merged in GitHub Action…
How to Control Preview Environment Cost in GitHub ActionsKeep per-PR preview environments cheap in GitHub Actions by deploying only on labels, scaling previews to zer…