How it works
- Boot — VMs are pre-booted from template images with CoW overlays, with a system app placeholder (
warmpool-{uuid}) - Ready — The VM has completed kernel boot and is waiting in the pool
- Claim — When a sandbox is created, a matching VM is atomically claimed using
FOR UPDATE SKIP LOCKED - Transfer — The claimed VM’s app ownership is transferred to the new sandbox
- Replenish — A background loop detects pools below target and boots replacement VMs (one at a time to avoid burst load)
Configuration
Enable and configure the warm pool in your server config:Setting a template’s pool size to
0 disables warm pooling for that template. Sandboxes for that template will always cold-boot.Checking pool status
View the current state of the warm pool:- CLI
- API
The pool status endpoint is admin-only.
Graceful fallback
If the warm pool is empty or disabled, sandbox creation falls back to cold booting a new VM. This is transparent to the caller — the only difference is latency:| Path | Typical latency |
|---|---|
| Warm pool claim | < 200ms |
| Cold boot | 2-3 seconds |
Concurrency safety
The claim operation uses PostgreSQL’sFOR UPDATE SKIP LOCKED to safely handle concurrent sandbox creation:
- Multiple requests arriving simultaneously each get a different VM
- If no VMs are available, the query returns no rows (no blocking, no contention)
- The replenisher only boots one VM per cycle to avoid overloading the host
Resource considerations
Warm pool VMs consume host resources (CPU, memory, TAP devices, IP allocations) even when idle. Size your pool targets based on:- Expected sandbox creation rate — Higher rates benefit more from warm pooling
- Available host resources — Each warm VM uses its configured preset’s CPU and memory
- Template popularity — Allocate more warm VMs to frequently-used templates
- Acceptable cold-boot rate — A smaller pool means more cold boots during traffic spikes