Skip to content
Latchkey

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) plus workflow_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"
          done

Gotchas

  • 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

Run this faster and cheaper on Latchkey managed runners. Start free →