Skip to content
Latchkey

How to Run Compose on Self-Hosted Runners

Self-hosted runners persist state between jobs, so leftover Compose containers and volumes are the main risk and cleanup is the fix.

Because a self-hosted runner is not fresh each run, isolate every job with a unique project name and always tear down, so one job never inherits another job's containers or volumes.

Steps

  • Set a unique -p project name per job or run.
  • Always run docker compose down -v at the end, even on failure.
  • Prune dangling images periodically so disk does not fill.

CI job

.github/workflows/ci.yml
jobs:
  test:
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v4
      - run: docker compose -p ci-${{ github.run_id }} up -d --wait
      - run: npm run test:int
      - if: always()
        run: docker compose -p ci-${{ github.run_id }} down -v --remove-orphans

Gotchas

  • Without a unique project name, two concurrent jobs on one runner clash over container names.
  • Latchkey managed runners are ephemeral and auto-heal transient failures, so this class of leftover-state flake does not occur.

Related guides

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