Documentation menu
Getting started
Dashboard & analytics
- Dashboard at a glance
- Cost analysis
- Pipeline performance
- Optimization insights
- Knowledge Base
- Connect your AI agent
Managed runners
- Runners overview
- Run your first job
- Migrate from GitHub-hosted
- Latchkey CLI
- The Runners page
- Custom runners (AI Scan)
- Self-healing
- Runner image & software
- Provisioning & warm pools
- Limits & concurrency
Caching
Team & notifications
Billing & plans
Help
How provisioning works
What happens between a job queueing on GitHub and a runner picking it up: warm pools, cold starts with just-in-time registration, the concurrency ceiling, and why a job might wait.
When GitHub queues a job with a latchkey-* label, a webhook tells Latchkey immediately, and Latchkey makes one decision: hand the job to a runner that is already warm, or launch a fresh machine for it. You never see that decision, but it is the difference between a pickup in a few seconds and one in about ten, and it explains most of what this page covers.
latchkey-* labelWarm pickup vs cold start#
A warm pickup means a pre-provisioned runner was already online for your workspace: the job is handed straight to it and starts within a few seconds. A cold start means no warm runner fit, so a fresh machine boots just for that job, registers with GitHub using a just-in-time, single-use configuration, and is running your steps in about 10 seconds. Both paths end identically: the runner takes exactly one job and the machine is terminated when the job finishes.
Warm pools#
| Plan | Warm pool |
|---|---|
| Developer | One warm latchkey-small runner plus parked capacity |
| Launch | The same baseline: one warm runner plus parked capacity |
| Scale | The same baseline: one warm runner plus parked capacity |
Every plan gets the same warm baseline today, and it covers latchkey-small only: one always-on warm runner backed by parked machines that resume in seconds. Anything beyond that, and any job asking for a larger size, cold-starts in about 10 seconds. Warm capacity costs you nothing while it idles; billing is per job minute, and an idle warm runner is not running a job.
Ephemeral, always#
Provisioning never reuses a machine. Warm or cold, a runner takes exactly one job and is terminated afterward, along with its disk, which is why runner names in the GitHub run view change on every run and why anything a job writes to local disk is gone when the job ends. The security side of this design, just-in-time credentials, private networking, and encrypted single-use disks, is covered in Security architecture.
Concurrency#
A workspace runs up to 20 concurrently busy runners by default, and only busy runners count: idle warm runners never consume a slot, so warm capacity does not compete with your real jobs. When a burst needs more than 20 at once, the overflow jobs stay queued until a slot frees, then start on their own; nothing errors and nothing is lost. If your peaks queue regularly, higher limits are available, contact support.
Hard boundaries#
- Jobs are capped at 4 hours; the machine is terminated at 4 hours even if the job is still running.
- Runners are Ubuntu 24.04 LTS on x86_64 only: no Windows, macOS, arm64, or GPU hosts.
- Runners run in AWS us-east-1.
The full table, including disk sizes and per-plan custom configuration counts, is in Limits and concurrency.
Why a job might sit in queued#
When provisioning cannot or will not launch a runner, there is no error on GitHub's side; the job just waits. That is by design: jobs targeting latchkey-* labels stay queued on GitHub rather than erroring. The usual causes:
- A label typo: no configuration matches the label, so nothing ever picks the job up.
- The repository is not monitored, or the runner configuration is disabled.
- A billing or trial block: an expired trial, a lapsed subscription, or an exhausted free tier on a card-less trial. A "Managed runner blocked" notification fires when this happens, at most once per day.
- A custom runner's image is still building; jobs targeting its label wait until the build completes.
- The workspace is at its 20-busy-runner ceiling; the job starts as soon as a slot frees.
The symptom-by-symptom walkthrough, with how to confirm each cause, is in Troubleshooting.
Why is my job sitting in queued?
Either it is waiting for capacity beyond the warm baseline, in which case a fresh machine cold-starts in about ten seconds, or something is blocking it: the label, monitoring, configuration, billing, an in-progress image build, or the concurrency ceiling. Check them in that order.
What is the difference between a warm pickup and a cold start?
A warm pickup hands the job to a machine that is already running, in a few seconds. A cold start provisions a new machine with just-in-time registration and takes about ten seconds. Every plan gets the same warm baseline today: one always-on warm runner plus parked capacity on latchkey-small.
Do idle warm runners count against my concurrency limit?
No. The default of 20 concurrent runners per workspace counts busy runners only, so warm capacity waiting for work never consumes the limit you are paying attention to.