Clone pools
A clone pool keeps a stack of pre-warmed copy-on-write clones of a golden
version ready in the data-plane cluster, so a developer's adj clone
fast-claims one instead of waiting on FSx to provision a fresh volume.
Why
Without a pool, an on-demand clone waits on FSx volume provisioning —
typically about 2 minutes to Ready. Under FSx load it can stretch to
around 10 minutes: CreateVolume calls serialize at roughly one per minute
per cluster, so requests queue behind each other during maintenance or
scaling windows (that's why --wait's timeout is generous). With a pool,
adj clone claims an already-provisioned volume instead: a warm claim
reaches Ready in about 15–30 seconds (measured p50 15s / p95 30s) —
seconds instead of minutes.
If your team clones often — CI, onboarding, a busy sprint — a pool is the difference between "grab a coffee" and "it's already there."
Creating a pool
$ adj pool create prod-pg16 --target-warm 5
Pool 8f4b2c1a-3d5e-4a7b-9c0d-1e2f3a4b5c6d created for prod-pg16 v3 (target 5 warm). Filling in the background.
adj pool create <golden> pins the latest ready version of <golden> at
creation time and asks the data-plane cluster to keep --target-warm warm
clones of it around (default 5). --max-warming caps how many provisions can
be in flight at once (default 2) — since FSx volume creation is
rate-limited, the pool fills gradually rather than all at once.
A pool pins one version
A pool does not auto-follow new golden versions. If you run adj import run again and build prod-pg16 v2, the pool keeps warming v1 clones until
you refresh it — remove and recreate:
$ adj pool rm <pool-id>
$ adj pool create prod-pg16 --target-warm 5
The new pool picks up whatever is the latest ready version at the moment you recreate it.
Claim behavior
When a developer runs adj clone prod-pg16, the control plane looks for a
warm clone in a pool for that golden first. If one is available, it's
fast-claimed — reassigned to the developer's namespace — instead of
triggering a fresh FSx CreateVolume. If no warm clone is available (pool
empty, still filling, or no pool exists), the clone falls back to the
on-demand path automatically. Either way the command is the same; only the
wait time differs. adj clone --wait reports readiness regardless of which
path was taken.
Pool claims go through the same adj clone request as an on-demand clone, so
the same org/per-user instance quota check applies either way — a pool
doesn't let you clone past your cap, it just makes the clones inside it
faster. See Users and quotas.
Inspecting pools
$ adj pool ls
$ adj pool get <id>
adj org usage also has a POOLS section (warm count vs. target, one line
per golden) if you want the whole org's pool state at a glance.
Removing a pool
$ adj pool rm 8f4b2c1a-3d5e-4a7b-9c0d-1e2f3a4b5c6d
Remove pool 8f4b2c1a-3d5e-4a7b-9c0d-1e2f3a4b5c6d and drain its warm clones? [y/N]: y
Pool 8f4b2c1a-3d5e-4a7b-9c0d-1e2f3a4b5c6d removed.
adj pool rm takes the pool id (from adj pool ls), not the golden
name.
adj pool rm tombstones the pool and drains its warm, unclaimed clones
in the data plane — those are destroyed. Instances a developer has already
claimed out of the pool are untouched; they're regular instances now and
follow the normal instance lifecycle (reset / refresh / destroy).
--yes skips the confirmation prompt.
Next
- Goldens and imports — how the version a pool pins gets built in the first place.
- Cluster operations — cluster health
matters for pool fill rate; check
adj cluster status.