Skip to content
Latchkey LogoLatchkey home

What is installed on ubuntu-latest: the GitHub Actions runner image

What is installed on ubuntu-latest is whatever the current Ubuntu 24.04 runner image ships, because the ubuntu-latest label resolves to ubuntu-24.04 today. The versions below are from the image README read on 2026-09-20, beside the same commands run on a Latchkey runner the same day.

Label chain: ubuntu-latest resolves to ubuntu-24.04, then to a dated image version
Three names, three lifetimes. Only the middle one is stable enough to pin, and only the last one is what actually ran your job.
Recorded log of 21 tool versions printed on a Latchkey latchkey-small Ubuntu 24.04 runner
The same version script on a Latchkey latchkey-small runner, 2026-09-20, from content/repro/whats-installed-on-ubuntu-latest.sh.

Two questions bring people here. The first is whether a tool is on the machine already, so a workflow can call it without a setup step. The second is which version, because a job that works on one image release breaks on the next when a major version moves under it.

Both answers change every few weeks. Treat the table below as a snapshot with a date on it, and treat the last section, printing the versions from inside your own job, as the answer that never goes stale.

What ubuntu-latest resolves to today

ubuntu-latest is a label, not an image. It currently points at ubuntu-24.04, which GitHub states in its hosted-runner reference and in the runner-images repository, where the available-images table lists the YAML labels for that image as "ubuntu-latest" or "ubuntu-24.04". Both were read on 2026-09-20.

Behind the label sits a specific build. The Ubuntu 24.04 README on the same day reported OS version 24.04.5 LTS, kernel 6.17.0-1022-azure and image version 20260907.300.1. Those rebuild continuously, which is why a job can start failing without a workflow change: the image moved, not your YAML.

The label itself moves too, and slowly. The runner-images repository says the -latest label is used for the latest OS image version that is generally available, and that the migration is gradual, over one to two months, so workflows can adapt. GitHub's own reference adds the caveat that -latest images are the latest stable images GitHub provides and might not be the most recent version the OS vendor has released.

The versions, side by side

The left column is the GitHub image README read on 2026-09-20. The right is the same tool printed by content/repro/whats-installed-on-ubuntu-latest.sh on a Latchkey latchkey-small runner the same day. They are two different images and the second column is here to make that concrete rather than to claim parity.

ToolGitHub ubuntu-24.04 (image 20260907.300.1)Latchkey latchkey-small
OSUbuntu 24.04.5 LTS, kernel 6.17.0-1022-azureUbuntu 24.04.4 LTS, kernel 6.17.0-1019-aws
Node.js (default)22.23.2v20.20.2
Node.js (cached)22.23.2, 24.20.0Node 20, 22 and 24 in the toolcache
npm10.9.810.8.2
Yarn1.22.221.22.22
Python3.12.3 (cached: 3.10 to 3.14)Python 3.12.3
pip24.0pip 24.0
Ruby3.2.3 (cached: 3.2 to 4.0)ruby 3.2.3
Go1.24.13, 1.25.14, 1.26.8go1.24.13
Java (default)17.0.20+1, plus 8, 11, 21 and 25openjdk 17.0.20.1
.NET SDK8.0.130 through 10.0.40010.0.400
PHP8.3.6PHP 8.3.6
Docker client28.0.429.7.2
Docker Compose2.38.2v5.5.0
Docker Buildx0.37.0v0.36.1
Git2.55.02.55.0
GitHub CLI2.100.02.98.0
AWS CLI2.36.402.36.31
Azure CLI2.90.0not printed by the script
Google Cloud CLI583.0.0582.0.0
kubectl1.37.0a development build string, not a release
Helm3.21.4not printed by the script
gcc / GNU C++12.4.0, 13.3.0, 14.2.0gcc 14.2.0
Clang16.0.6, 17.0.6, 18.1.3not printed by the script
CMake3.31.64.4.2
Maven / Gradle / Ant3.9.16 / 9.7.1 / 1.10.14Maven, Gradle and Ant preinstalled
Google Chrome152.0.7977.82152.0.7977.64
Firefox / Edge155.0 / 152.0.4191.66Firefox and Edge preinstalled
Selenium server4.48.0Selenium preinstalled
PostgreSQL / MySQL16.15 / 8.0.46, both disabled at boot16 / 8.0, both disabled at boot
jq / yq1.7 / 4.53.6jq preinstalled

What is not on the image

Absent from the Ubuntu 24.04 README on 2026-09-20: pnpm, Bun, Deno and Terraform. pnpm and Bun arrive through Corepack or their own installers. Terraform is the one that catches people, because it shipped on ubuntu-22.04 and does not ship here: actions/runner-images#13876 is the tool request filed when ubuntu-latest moved to 24.04, and a workflow that expects it now needs hashicorp/setup-terraform or an explicit install step.

Present but not running: PostgreSQL 16.15 and MySQL 8.0.46 are installed and disabled at boot, so a job that needs either starts the service itself with sudo systemctl start postgresql.service or the MySQL equivalent. A service container is usually the better answer, because it pins the version.

The general rule is to install what you need rather than assume it. apt-get install in a step works for system packages, the setup-* actions are faster for language runtimes because they resolve from the toolcache, and anything heavier belongs in a container image you control.

.github/workflows/ci.yml
- name: Install what the image does not ship
  run: |
    corepack enable pnpm
    sudo apt-get update && sudo apt-get install -y --no-install-recommends libgbm1
- uses: actions/setup-node@v7
  with:
    node-version: 22
    cache: npm

Print the versions from inside your own job

The only list that is true for your run is the one your run prints. Drop this step in front of the job you are debugging: it costs a second, and it turns "the image must have changed" from a theory into a line you can diff against the previous run.

.github/workflows/ci.yml
- name: Image and tool versions
  run: |
    cat /etc/os-release | head -2
    echo "image: ${ImageOS:-unknown} ${ImageVersion:-unknown}"
    node --version; npm --version; python3 --version
    go version; java -version; docker --version
    docker compose version; git --version; gh --version | head -1

The same script on a Latchkey runner

A Latchkey runner is not a GitHub-hosted runner, and the point of running the same script on one is to show the difference rather than to imply there is none. The documentation describes the fleet as Ubuntu 24.04 LTS on x86_64, on AWS m6a-class hardware, with a preinstalled toolchain and a GitHub-parity toolcache at /opt/hostedtoolcache, so actions/setup-node and friends resolve instantly instead of downloading.

What that parity does not mean is identical versions. In the run below Node is 20.20.2 rather than 22.23.2, Docker is a major version ahead, and CMake is 4.4.2 against the GitHub image's 3.31.6. If your workflow depends on a default version rather than a setup-* action pinning one, that is the kind of difference that will find you.

latchkey run, recorded 2026-09-20 on latchkey-small
image:           Ubuntu 24.04.4 LTS (x86_64, kernel 6.17.0-1019-aws)
node             v20.20.2
npm              10.8.2
yarn             1.22.22
python3          Python 3.12.3
pip3             pip 24.0 from /usr/lib/python3/dist-packages/pip (python 3.12)
ruby             ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux-gnu]
go               go version go1.24.13 linux/amd64
java             openjdk version "17.0.20.1" 2026-08-18
dotnet           10.0.400
php              PHP 8.3.6 (cli) (built: Jul 16 2026 18:30:41) (NTS)
docker           Docker version 29.7.2, build a7dcaa6
docker compose   Docker Compose version v5.5.0
buildx           github.com/docker/buildx v0.36.1 1d8dde89b8aba914e05e45366770736fea1fd690
git              git version 2.55.0
gh               gh version 2.98.0 (2026-08-20)
aws              aws-cli/2.36.31 Python/3.14.6 Linux/6.17.0-1019-aws exe/x86_64.ubuntu.24
gcloud           Google Cloud SDK 582.0.0
kubectl          Client Version: v0.0.0-master+$Format:%H$
gcc              gcc (Ubuntu 14.2.0-4ubuntu2~24.04.1) 14.2.0
cmake            cmake version 4.4.2
chrome           Google Chrome 152.0.7977.64 

The disk all of this is sitting on

A standard GitHub-hosted Linux runner gives the job 14 GB of SSD, with 4 vCPU and 16 GB of RAM on a public repository and 2 vCPU and 8 GB on a private one, per GitHub's hosted-runner reference read on 2026-09-20. The preinstalled toolchain in the table above is sitting in that 14 GB before your job starts.

That is why the two most common failures on this image are about space rather than software. Freeing disk space on GitHub Actions runners measures what each toolchain directory gives back, and no space left on device covers the failure itself, including the variant that reports the same error with a half-empty disk.

Key takeaways

  • ubuntu-latest means ubuntu-24.04 today, and the migration to the next release takes one to two months.
  • Pin runs-on: ubuntu-24.04 when a version matters; the label will move without asking.
  • pnpm, Bun, Deno and Terraform are not on the image; PostgreSQL and MySQL are, but are not running.
  • Print ImageOS and ImageVersion in the job so image drift is visible in the log.

Frequently asked questions

Is ubuntu-latest 22.04 or 24.04?
24.04. The runner-images available-images table lists "ubuntu-latest" or "ubuntu-24.04" as the labels for that image, read on 2026-09-20. The Ubuntu 22 images are on the way out: the repository announcement (actions/runner-images#14254) says they began deprecation on 17 September 2026 and are fully unsupported from 17 April 2027 for GitHub Actions and Azure DevOps.
How do I pin the runner image?
Use the versioned label, runs-on: ubuntu-24.04, rather than ubuntu-latest. That pins the OS release but not the build: image versions still roll forward underneath it, so record ImageVersion in the job if you need to know exactly which one ran. There is no label that pins a specific image build, which is what actions/runner-images#13034 asks for.
How do I install a tool that is not preinstalled?
For system packages, sudo apt-get update && sudo apt-get install -y <package> in a step. For language runtimes, prefer the setup-* actions, which resolve from the toolcache instead of downloading. For anything large or slow, bake it into a container image. Tool requests such as actions/runner-images#13876, filed when Terraform left the image, are what the alternative looks like: waiting for someone else to add it.
Why did my job run out of disk after an ubuntu-latest image update?
Because the image grew into headroom your job was quietly relying on. The toolchains in the table are rebuilt continuously and a new one can take a gigabyte you were using. Add a cleanup step ahead of the heavy work rather than treating it as a one-off, and record df -h on failure so the next occurrence arrives with evidence.

Related guides

References

Latchkey publishes the software on its runner image, so you can read it before a job lands there. Start free → 30-day trial · No credit card