Skip to content
LatchkeyLatchkey home

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

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

WhatPathEnvironment variable
Home directory/home/runnerHOME
Your checked-out code/home/runner/work/<repo>/<repo>GITHUB_WORKSPACE
Work root for all repos/home/runner/workRUNNER_WORKSPACE is one level in
Scratch space for the run/home/runner/work/_tempRUNNER_TEMP
Preinstalled tool versions/opt/hostedtoolcacheRUNNER_TOOL_CACHE

Other hosted operating systems

RunnerHomeTool cache
Ubuntu/home/runner/opt/hostedtoolcache
macOS/Users/runner/Users/runner/hostedtoolcache
WindowsC:\Users\runneradminC:\hostedtoolcache\windows

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.

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.

Frequently asked questions

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.

Related guides

References

Run this faster and cheaper on Latchkey managed runners - self-healing included. Start free → 30-day trial · No credit card