Skip to content
Latchkey

How to Use a Throwaway Database Per Job in GitHub Actions

A service container is created fresh for each job and torn down when the job finishes, so every job already gets an isolated, throwaway database.

Each job that declares a services: database gets its own container instance. Matrix legs and parallel jobs never share state, which makes the database effectively disposable: create the schema, run, and let the runner discard it.

Steps

  • Declare the database under the job services: block.
  • Create the schema (migrate) at the start of the job.
  • Do no cleanup; the container is destroyed when the job ends.

Workflow

.github/workflows/ci.yml
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        shard: [1, 2, 3]   # each shard gets its own fresh postgres
    services:
      postgres:
        image: postgres:16
        env: { POSTGRES_PASSWORD: postgres, POSTGRES_DB: app_test }
        ports: [5432:5432]
        options: --health-cmd "pg_isready -U postgres" --health-interval 10s --health-retries 5
    env:
      DATABASE_URL: postgres://postgres:postgres@localhost:5432/app_test
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npx prisma migrate deploy
      - run: npm test -- --shard=${{ matrix.shard }}/3

Gotchas

  • Within a single job, all steps share the same database; use separate jobs or schemas to isolate parallel test workers.
  • Because the container is discarded, never rely on data persisting to a later job; pass artifacts or re-seed instead.

Related guides

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