Quick answer: GitHub will begin moving the x64 ubuntu-latest label from Ubuntu 24.04 to Ubuntu 26.04 on October 19, 2026, with the gradual rollout scheduled to finish on November 19, 2026. Existing workflow YAML does not need a label change for the migration to happen: jobs using runs-on: ubuntu-latest can start landing on Ubuntu 26.04 during that window. Test with ubuntu-26.04 now; if you need time, temporarily pin affected jobs to ubuntu-24.04.[1][4]
Safe default: Do not replace every label blindly. First inventory affected jobs, add a temporary 24.04/26.04 test matrix, fix undeclared dependencies, and only then choose either an explicit
ubuntu-26.04pin or a documented return toubuntu-latest.
Copy-paste migration matrix
Add a temporary manual workflow or adapt one non-deployment job. This checks both images without changing your production runner:
name: Ubuntu 26.04 compatibility
on:
workflow_dispatch:
pull_request:
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-26.04]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
# Keep your normal setup actions here.
# Example: actions/setup-node, setup-python, setup-java, etc.
- name: Record runner and tool versions
run: |
cat /etc/os-release
uname -a
java -version || true
python --version || true
node --version || true
docker version || true
docker compose version || true
helm version --short || true
git --version
- name: Install dependencies
run: YOUR_INSTALL_COMMAND
- name: Test
run: YOUR_TEST_COMMAND
- name: Build
run: YOUR_BUILD_COMMAND
Replace the three placeholder commands. Keep deployment, publishing, migrations, and other side effects out of this first compatibility run.
What is changing and when?
Ubuntu 26.04 and its Arm64 image completed public preview and became generally available for GitHub Actions and Azure DevOps on September 17. The explicit labels are ubuntu-26.04 for x64 and ubuntu-26.04-arm for Arm64.[1][3]
The separate ubuntu-latest change applies to the x64 label. GitHub says the gradual migration starts October 19 and is planned to finish November 19. During this period, two runs of unchanged YAML can use different underlying Ubuntu releases as rollout progresses.[1][4]
GitHub’s hosted-runner reference currently lists ubuntu-latest, ubuntu-24.04, and ubuntu-26.04 as available x64 labels. It also warns that a -latest image means GitHub’s latest stable image, which is not necessarily the newest operating-system release available from the OS vendor.[2]
Why an unchanged workflow can break
ubuntu-latest is a moving alias, not a permanent Ubuntu version. GitHub warns that workflows depending on Ubuntu 24.04-specific software, package versions, system libraries, compilers, prebuilt binaries, or architecture-specific dependencies may be affected.[1][3][4]
The current image manifests show material differences beyond the OS name. At the time checked, the Ubuntu 24.04 image listed Node.js 22, Python 3.12, Ruby 3.2, PHP 8.3, Helm 3, Docker 28, Docker Compose 2, PostgreSQL 16, and OpenSSL 3.0 as image-level defaults or installed tools. The Ubuntu 26.04 manifest listed Node.js 24, Python 3.14, Ruby 3.3, PHP 8.5, Helm 4, Docker 29, Docker Compose 5, PostgreSQL 18, and OpenSSL 3.5.[5][6]
These manifests are regenerated as runner images change. Treat the figures as a point-in-time warning, not a promise that every future image will keep exactly those versions.[5][6]
High-risk dependency patterns
Check these first:
- scripts that call
python,ruby,php,java,node,gcc,clang,helm,docker,psql, ormysqlwithout a setup action or explicit version; - exact runtime patch pins that may not have a build for Ubuntu 26.04;
- native modules, wheels, gems, or binaries compiled against older system libraries;
- Docker and Docker Compose behavior that depends on a major version;
- Helm charts or scripts written for Helm 3 assumptions;
- database integration tests that assume PostgreSQL 16 or MySQL 8.0 behavior;
- browser tests tied to a particular Chrome, Firefox, driver, or Selenium version;
- APT package names, repositories, signing keys, or packages removed from the new Ubuntu release;
- shell scripts that rely on version-specific output or deprecated flags;
- reusable workflows and composite actions that hide their own
runs-onor system-tool assumptions.
Important documentation mismatch: verify Java at runtime
GitHub’s migration issue currently says Java 17 remains the default, while the live Ubuntu 26.04 image manifest currently marks Java 25 as default. The tracking discussion also flags this discrepancy.[4][5]
Do not build a migration decision on either sentence alone. If Java matters, use actions/setup-java with the required version and log java -version in the compatibility job. The same rule applies to every critical runtime: install or select it explicitly rather than trusting the image default.
Seven-step migration plan
1. Inventory every use of ubuntu-latest
Search .github/workflows/, reusable workflows, called workflows in other repositories, and organization starter workflows. A basic local search is:
git grep -n "ubuntu-latest" -- '.github/workflows/*.yml' '.github/workflows/*.yaml'
Also inspect matrix values and variables that resolve to runner labels. git grep will not reveal labels hidden in remote reusable workflows.
2. Classify jobs by risk
Use three groups:
| Risk | Typical job | First action |
|---|---|---|
| Low | linting with fully pinned setup actions | Run on both images |
| Medium | tests using services, browsers, native packages, or APT | Matrix test plus version logs |
| High | releases, deployments, signing, database migrations, production infrastructure | Clone as a non-deploying validation job first |
A green lint job does not prove a release or deployment job is safe.
3. Make language and tool versions explicit
Prefer maintained setup actions or your project’s normal version manager. Pin the runtime your application supports, not whatever happens to be first on PATH. Examples include actions/setup-node, actions/setup-python, and actions/setup-java.
For system tools, record the expected major version and install it deliberately when reproducibility matters. Avoid assuming the hosted image’s preinstalled inventory is an application dependency contract.
4. Run the two-image matrix
Compare more than pass/fail:
- dependency resolution and lockfile changes;
- test results and skipped tests;
- warnings and deprecations;
- built artifact names, checksums, sizes, and architectures;
- Docker image manifests and startup behavior;
- database schema or integration-test output;
- deployment plans without applying them;
- execution time and cache hit behavior.
Do not upload both matrix artifacts under the same filename if one can overwrite the other. Include ${{ matrix.os }} in artifact names.
5. Fix the workflow, not just the symptom
A temporary ubuntu-24.04 pin is a rollback lever, not a complete migration. The durable fix is usually to declare the missing runtime, package, library, or container dependency and test it explicitly.
If an old runtime cannot run on Ubuntu 26.04, decide whether to upgrade it, keep only that matrix entry on 24.04 temporarily, or move the job into a maintained container. Document an owner and removal date for any temporary pin.
6. Choose your label deliberately
Use:
runs-on: ubuntu-26.04
when you want an explicit operating-system generation and controlled future upgrades.
Use:
runs-on: ubuntu-latest
when you accept GitHub-managed stable-image migrations and continuously test for them.
Use:
runs-on: ubuntu-24.04
only as a temporary compatibility hold when the job is not ready. GitHub explicitly identifies the 24.04 pin as the mitigation during this transition.[1][4]
7. Monitor the rollout and preserve evidence
During October 19–November 19, record /etc/os-release and the critical tool versions in failed job logs. Check GitHub’s runner-image tracking issue and image manifests before assuming an unexplained failure is an application regression.[4][5]
If you find an image-specific problem, reproduce it with the explicit ubuntu-26.04 label and report it to the actions/runner-images repository with the “Set up job” image details, a minimal workflow, and the failing log section.
Rollback snippet
If production CI starts failing during the rollout and you need an immediate reversible hold:
jobs:
build:
# Temporary hold during the Ubuntu 26.04 migration.
# Owner: TEAM_OR_PERSON
# Remove by: YYYY-MM-DD
runs-on: ubuntu-24.04
Open a follow-up issue in the same change. A pin with no owner or removal date tends to become permanent debt.
30-minute readiness checklist
- [ ] Find every local and reusable workflow using
ubuntu-latest. - [ ] Identify release, deployment, signing, native-build, browser, and database jobs.
- [ ] Add a 24.04/26.04 matrix to a safe test path.
- [ ] Log
/etc/os-releaseand critical runtime/tool versions. - [ ] Replace image-default runtime assumptions with explicit setup steps.
- [ ] Compare artifacts and deployment plans, not only unit tests.
- [ ] Check Docker, Compose, Helm, databases, OpenSSL, compilers, and native packages.
- [ ] Pin only blocked jobs to
ubuntu-24.04. - [ ] Add an owner and deadline to every temporary pin.
- [ ] Re-run the explicit 26.04 job after each fix.
- [ ] Monitor the runner-image tracking issue through November 19.
Frequently asked questions
Will my existing ubuntu-latest workflow update automatically?
Yes. GitHub says jobs using the x64 ubuntu-latest label will gradually move from Ubuntu 24.04 to Ubuntu 26.04 between October 19 and November 19, 2026. You do not need to edit the label for the automatic migration to happen.[1][4]
How can I test Ubuntu 26.04 before my repository is migrated?
Set a test job to runs-on: ubuntu-26.04. For Arm64, use ubuntu-26.04-arm. Both images are generally available for production workloads.[1][3]
How do I stay on Ubuntu 24.04 temporarily?
Change affected jobs to runs-on: ubuntu-24.04. Treat this as a temporary hold, assign an owner, and continue testing on 26.04.[1][4]
Does this change Arm64 ubuntu-latest?
GitHub’s announcement describes the automatic alias migration for the x64 ubuntu-latest label. Arm64 has explicit ubuntu-24.04-arm and ubuntu-26.04-arm labels in the hosted-runner reference; do not assume the x64 alias behavior applies to an Arm64 label that is not documented.[2][4]
Is Java 17 or Java 25 the default on Ubuntu 26.04?
GitHub’s migration issue and current image manifest disagree: the issue says Java 17, while the live manifest marks Java 25 as default. Use actions/setup-java and verify with java -version instead of relying on the image default.[4][5]
Should I pin ubuntu-26.04 or keep ubuntu-latest after testing?
Pin ubuntu-26.04 if controlled OS upgrades and reproducibility are more important. Keep ubuntu-latest if you intentionally want GitHub’s current stable image and have recurring compatibility tests. Neither choice removes the need to pin critical application runtimes.
Last checked: October 18, 2026. Runner image contents are updated regularly; verify the live image manifest before relying on a preinstalled version.
Sources
[1] https://github.blog/changelog/2026-09-17-ubuntu-26-generally-available-and-latest-migration — GitHub: Ubuntu 26 generally available and ubuntu-latest migration
[2] https://docs.github.com/en/actions/reference/runners/github-hosted-runners — GitHub Docs: GitHub-hosted runners reference
[3] https://github.com/actions/runner-images/issues/14747 — GitHub runner-images: Ubuntu 26.04 GA and software differences
[4] https://github.com/actions/runner-images/issues/14748 — GitHub runner-images: ubuntu-latest migration tracking issue
[5] https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2604-Readme.md — GitHub runner-images: Ubuntu 26.04 installed software
[6] https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md — GitHub runner-images: Ubuntu 24.04 installed software