# GitHub Runner Home Directory, and Why It Is Not the Working Directory

> The real filesystem paths on a GitHub Actions runner: HOME, the workspace, the temp and tool-cache directories, how container jobs relocate HOME, and what changes on self-hosted runners.

Source: https://latchkey.dev/learn/runner-reference/github-runner-home-directory  
Updated: 2026-08-31

On a GitHub-hosted Linux runner, HOME is /home/runner and your checked-out code is not in it. Almost every confusing path problem in CI comes from assuming those are the same directory.

A step that writes to `~/.npmrc` and a step that writes to `./.npmrc` are writing to two different places on a runner, three directories apart. Locally they often amount to the same thing because you work inside your own home directory.

These are the paths as they actually are, plus the two cases that surprise people: container jobs, where HOME moves, and self-hosted runners, where it depends on who installed the service.

## Paths on a hosted Linux runner

| What | Path | Environment variable |
| --- | --- | --- |
| Home directory | `/home/runner` | `HOME` |
| Your checked-out code | `/home/runner/work/<repo>/<repo>` | `GITHUB_WORKSPACE` |
| Work root for all repos | `/home/runner/work` | `RUNNER_WORKSPACE` is one level in |
| Scratch space for the run | `/home/runner/work/_temp` | `RUNNER_TEMP` |
| Preinstalled tool versions | `/opt/hostedtoolcache` | `RUNNER_TOOL_CACHE` |

> The default working directory for every `run` step is GITHUB_WORKSPACE, not HOME. That is the whole distinction: `cd ~` moves you out of your repository.

## Other hosted operating systems

| Runner | Home | Tool cache |
| --- | --- | --- |
| Ubuntu | `/home/runner` | `/opt/hostedtoolcache` |
| macOS | `/Users/runner` | `/Users/runner/hostedtoolcache` |
| Windows | `C:\Users\runneradmin` | `C:\hostedtoolcache\windows` |

> The Windows workspace has historically been on the D: drive, and the drive letter is a property of the image rather than a guarantee. Read `GITHUB_WORKSPACE` instead of hardcoding a path, on every platform.

## Container jobs move HOME

When a job specifies a `container:`, steps do not run as the runner user in the runner filesystem. HOME is set to `/github/home`, which is a bind mount of `/home/runner/work/_temp/_github_home` from the host, and the workspace is mounted at `/__w/<repo>/<repo>`. Anything an action or tool writes to `~` therefore lands in that mounted directory, not in `/home/runner` and not in your repository. It does survive between steps of the same job, because the mount is shared, and it does not survive the job.

> This is the usual explanation for a credentials file, a tool config or a language package cache that a container job writes successfully and a later job cannot find.

## Self-hosted and managed runners

- Self-hosted: HOME belongs to the operating-system user running the runner service, so it is whatever that account is. The work directory is `_work` inside the runner installation directory rather than under `/home/runner`.
- Because self-hosted runners are reused between jobs, whatever a job leaves in HOME is visible to the next one. That is occasionally a useful cache and always a security consideration, since one repository can read what another left behind.
- Latchkey runners are ephemeral and Ubuntu-based, so the hosted Linux paths above apply and nothing persists in HOME between jobs by construction.

## Where this bites

- Cache actions that key on a path under `~` while the tool actually writes inside the workspace, or the reverse. Print the path in a step before caching it.
- Credentials helpers. `docker login`, `gh auth` and `git config --global` all write to HOME, so on a self-hosted runner they outlive the job.
- Scripts that use `~` and get run inside a container step, where `~` is `/github/home` and not the directory the earlier steps wrote to.
- Disk space. The workspace and HOME share the same volume on hosted runners, so a large dependency cache in HOME reduces the room available for a build.

## FAQ

### What is the home directory on a GitHub Actions runner?

On hosted Linux runners it is `/home/runner`, on macOS `/Users/runner`, and on Windows `C:\Users\runneradmin`. In a container job HOME is `/github/home` instead. Read the `HOME` environment variable rather than assuming, since a container step changes it.

### Is the home directory the same as the workspace?

No. HOME is `/home/runner` and your checked-out repository is at `/home/runner/work/<repo>/<repo>`, which is what `GITHUB_WORKSPACE` points to and where every `run` step starts. They are on the same disk and are not the same directory.

### Does anything written to the home directory persist between jobs?

Not on hosted or on any ephemeral runner: the machine is destroyed when the job ends. On a self-hosted runner it does persist, because the machine is reused, which is why credentials written by `git config --global` or `docker login` remain available to whatever runs next.

### How do I find the home directory during a run?

Add a step that echoes it: `run: echo "$HOME"`, alongside `echo "$GITHUB_WORKSPACE"` and `pwd`. On a job you suspect of a path problem this is faster than reasoning about it, and it is the only reliable answer inside a container.

---

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
