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