Skip to content

How to maintain the scratch org pool

Pools only stay useful if they are kept full and free of stale orgs. This guide covers the operator tasks. For how pooling works, see scratch org pooling.

One-time: make the DevHub pooling-ready

Pooling stores its state in custom fields on the DevHub's ScratchOrgInfo. Deploy the pooling metadata once per DevHub:

npm run org:pool:activate -- --target-org <devhub>

This installs the ScratchOrgInfo fields, the allocation-race validation rule, and the pooling permission sets. Until it runs, every pool command errors — the fields it queries do not exist.

Define a pool

Create config/project-<tag>-pool-def.json. Every key, its type and default is in the pool definition file reference; a working minimum:

{
    "tag": "ci",
    "maxAllocation": 10,
    "maxOrgsPerRun": 4,
    "durationDays": 1,
    "seedScript": "config/scratch-org-setup/ci-pool-seed.mjs",
    "seedBaseline": "branch:master"
}
  • Scale a pool out with more parallel pipeline steps, keeping steps × maxOrgsPerRun ≤ maxAllocation.
  • Leave seedConcurrency at its default of 4 — it is a property of the runner, not of the pool size (why).
  • Set seedBaseline when pull requests should delta-validate against pooled orgs; without it, orgs validate by full push.
  • seedScript is your own module — see write a pool seed script.

Top a pool up

npm run org:pool:prepare -- --devhubusername devhub --tag ci

It creates up to maxOrgsPerRun orgs (the exact formula is in the pool definition file reference), seeds each, stamps its baseline commit, and marks it available. On CI this is the scheduled per-tag Maintain … Pool pipeline (custom pipelines).

Inspect and release

npm run org:pool:list -- --devhubusername devhub          # totals per tag
node scripts/dia-scripts/index.mjs org pool-fetch --devhubusername devhub --tag ci   # claim one
node scripts/dia-scripts/index.mjs org pool-release --devhubusername devhub --username <org>  # return one

Clean up

npm run org:pool:cleanup -- --devhubusername devhub --tag ci

Deletes the pool's orgs wholesale (hub-side, by deleting the ScratchOrgInfo records). Add --allocated-only to remove just the claimed ones, or --id <recordId> for a single org.

Cleanup is an operator tool, not a schedule

cleanup removes every org for a tag. It is for resetting a pool, not routine maintenance — routine top-up is prepare on a schedule.