An ephemeral GitHub Actions runner is a fresh machine assigned to one job. It runs every step in that job, reports the result to GitHub, and is destroyed when the job finishes. The next job gets a different machine.
GitHub Actions runners managed by Depot work this way by default. Every job runs on a new, single-tenant virtual machine that has never run another customer's job. Depot manages registration, capacity, updates, and cleanup, so you get ephemeral runners without operating a runner fleet.
Switching an existing Linux job to Depot is usually a one line label change:
jobs:
test:
- runs-on: ubuntu-24.04
+ runs-on: depot-ubuntu-24.04The lifecycle of an ephemeral runner
A GitHub Actions workflow can contain several jobs. Each job is scheduled independently and gets its own runner. Steps inside one job share the same runner and filesystem until that job ends.
For a job using a Depot label, the lifecycle looks like this:
- GitHub queues the job and sends Depot a
workflow_jobwebhook. - Depot assigns a fresh virtual machine from a pre-provisioned standby pool that matches the requested runner label.
- Depot registers that runner with the GitHub organization.
- GitHub assigns the queued job to the runner.
- The runner executes every step in the job and sends logs and status back to GitHub.
- When the job completes, Depot terminates the virtual machine.
GitHub's own ephemeral self-hosted runner model follows the same one-job rule. GitHub automatically deregisters an ephemeral runner after it processes one job. If you operate the fleet yourself, you still need automation to create a clean machine, register it, collect its logs, and destroy it after deregistration.
That final cleanup step matters. Removing a runner registration from GitHub doesn't wipe the machine that hosted it.
State that disappears with the runner
Everything stored only on the runner's local disk disappears when the job ends:
- The checked-out repository and any uncommitted changes
- Installed packages and tool downloads
- Temporary files and environment variables
- Docker images, containers, and volumes created during the job
- Compiler output and package manager directories that weren't uploaded to a cache
- Processes and services started by workflow steps
This doesn't mean every step starts from zero. All steps in the same job use the same workspace. A dependency installed in step two is still available in step five. The boundary is the job, not the step.
Jobs in the same workflow don't share a local filesystem. If a build job creates a binary that a separate test
job needs, the workflow has to move that binary through external storage.
State that persists between jobs
Ephemeral runners separate compute from durable state. The runner disappears, but data explicitly uploaded to an external service can outlive it.
| State | How it persists | Best use |
|---|---|---|
| Dependency cache | actions/cache, a cache input on an actions/setup-* action, or a remote build cache | Dependencies and build output that can be regenerated |
| Workflow artifact | actions/upload-artifact and actions/download-artifact | Passing files between jobs or retaining output after a workflow |
| Container image | Push to a registry or use Depot's ephemeral registry | Moving a built image into testing or deployment |
| External service state | Object storage, databases, package registries, or another service reached by the workflow | Data that must remain available outside the job |
| Logs and job status | Sent to GitHub while the job runs, with additional metrics available in the Depot dashboard | Debugging and historical analysis |
GitHub distinguishes caches from artifacts. A cache is reusable data that makes future work faster. A workflow should still succeed when that cache misses. An artifact is an output you intentionally preserve or pass to another job.
The runners automatically accelerate actions/cache and cache-enabled actions/setup-* actions. Cache data lives
in Depot's distributed storage instead of on the runner, with transfers up to 1000 MiB/s. You keep the clean-machine
security model without downloading every dependency from its original source on every job.
Security and isolation
Long-lived runners accumulate state. A job can leave credentials, source code, modified tools, background processes, or files behind for the next job to find. Cleaning every possible location correctly is harder than destroying the machine.
Ephemeral runners remove that cross-job residue. GitHub assigns one job to the runner, and Depot destroys the entire virtual machine afterward. Depot GitHub Actions runners are also single tenant, so jobs don't share a VM with another customer.
The clean boundary doesn't make a workflow harmless. Code running inside the job can still access any secrets, tokens, network routes, and cloud permissions granted to that job. Keep permissions narrow, prefer short-lived OIDC credentials, and treat code from untrusted pull requests as untrusted.
Cold starts and cache misses
Creating a clean runner has a startup cost. The provider has to assign compute, boot the machine, register the runner with GitHub, and wait for GitHub to send the job. A long-lived runner that's already idle can accept work sooner, but you pay for that speed with idle capacity and a machine that must be cleaned between jobs.
Depot keeps fresh machines in pre-provisioned standby pools to reduce this startup path. A runner typically becomes ready in 10 to 45 seconds, with part of that time spent waiting for GitHub's control plane to register and connect the runner.
The runner still starts with an empty job filesystem. There are three practical ways to keep that from turning into repeated work:
- Put stable tools in the runner image. Depot provides GitHub-compatible images and supports custom runner images for teams with specialized dependencies.
- Store dependencies and incremental build output in an external cache. On Depot GitHub Actions runners, the standard GitHub cache actions use Depot Cache automatically.
- Upload outputs that another job needs as artifacts instead of assuming they will exist on the next runner.
Ephemeral runners make job isolation the default. Fast provisioning and external caching make that isolation practical without bringing back a fleet of long-lived machines.