# Ephemeral Runners Explained: Why One Job Per Machine Matters

> What an ephemeral CI runner is, how just-in-time registration works, and what changes about caching, secrets and debugging when every job gets a machine that is destroyed afterwards.

Source: https://latchkey.dev/learn/ci-explained/ephemeral-runners-explained  
Updated: 2026-08-20

An ephemeral runner executes exactly one job and is then destroyed. That single rule is what makes CI reproducible, and it is also what breaks every habit built on a machine that remembers.

A persistent runner is a long-lived machine that picks up job after job. It is cheap to operate and it accumulates state: leftover containers, a warm package cache, a global tool someone installed by hand two months ago. That accumulated state is why a build passes on one runner and fails on another, and why the fix is so often to reboot the box.

An ephemeral runner registers, runs one job, and terminates. Nothing survives it. Every job starts from the same image, which turns "works on the runner" into a statement about your code rather than about that machine.

## Ephemeral versus persistent, in the ways that matter

|  | Persistent runner | Ephemeral runner |
| --- | --- | --- |
| State between jobs | Retained, including state you did not intend | None |
| Reproducibility | Drifts as the machine ages | Identical every run |
| Secret exposure window | Machine lifetime | One job |
| Cache | Local disk, fast, uneven | External, keyed, consistent |
| Debugging | SSH in and look | Read the logs, or reproduce in a container |
| Cost shape | Idle capacity you pay for | Per job |

## How just-in-time registration works

A runner that lives for one job cannot hold a long-lived registration token, because a token that outlives the machine is a credential waiting to be reused. Just-in-time registration issues a single-use configuration at the moment a job is queued: the machine boots, claims exactly that job, and its credentials die with it. On Latchkey this takes about ten seconds from cold, or a couple of seconds when a warm machine is already waiting.

## What you have to change

- Cache through the cache action rather than relying on a warm local disk, because there is no local disk to be warm.
- Install tools in steps, or bake them into a runner image. A tool someone installed by hand is gone.
- Persist anything you need after the job as an artifact. Local files do not survive.
- Stop debugging by connecting to the machine. Reproduce in a container from the same image instead.
- Expect a per-job startup cost, and reduce the number of jobs rather than the isolation.

## What you get in return

The class of failure that starts with "it worked yesterday on the same commit" mostly disappears, because yesterday used a different machine and today does not. Secrets are exposed for the length of one job rather than the lifetime of a host. And capacity stops being a thing you plan: jobs are provisioned when they are queued, so idle machines are not something you pay for or forget to patch.

## Applying this to your pipeline

- Measure before changing. Most CI optimisation targets the wrong step because the slow one is assumed rather than timed.
- Cache what is expensive to produce and cheap to validate, and key the cache to the exact tool version.
- Fail fast: run the cheapest checks that can reject a change first, so an expensive job never starts on code that cannot pass.
- Prefer determinism over speed when they conflict. A fast pipeline nobody trusts gets re-run, which is slower than a slow one that is believed.

## FAQ

### What is an ephemeral runner?

A CI machine that runs exactly one job and is destroyed afterwards. Nothing carries over to the next job: no files, no installed tools, no cached layers and no credentials. Every job therefore starts from an identical image, which is what makes results reproducible.

### Are ephemeral runners slower than persistent ones?

Per job, slightly, because nothing is warm at the start. In practice the difference is small when provisioning is fast (Latchkey cold-starts in about ten seconds, or seconds from a warm pool) and it is usually repaid by not debugging failures that a dirty machine caused.

### How do ephemeral runners handle caching?

Through an external, keyed cache rather than local disk, because the disk does not survive the job. The cache is restored at the start of the job and saved at the end, so it behaves the same on every machine instead of depending on which host you landed on.

### Are ephemeral runners more secure?

They narrow one specific risk: the window in which a compromised job can reach another job. Credentials are single-use and the machine is destroyed, so there is no shared host to pivot through and no leftover checkout of someone else source. It is not a substitute for scoping permissions correctly.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
