GitHub Actions is changing runner images in June: check CI before it breaks

GitHub ActionsCI/CDDevOpsMigration

A CI/CD dashboard with several runner image lanes passing through a June migration checkpoint before GitHub Actions workflows run

Hook

GitHub Actions is changing several standard hosted runner labels in June 2026. If your CI has lived on windows-latest or macos-latest for years, this is a good moment to spend 30 minutes checking it before a release pipeline turns red at the worst possible time.

On May 14, GitHub announced two practical migrations. windows-latest and windows-2025 will gradually move to Windows Server 2025 with Visual Studio 2026 from June 8 to June 15. macos-latest will start moving from macOS 15 to macOS 26 on June 15, and that rollout will take 30 days.

Problem / Context

GitHub-hosted runners are convenient because GitHub maintains the virtual machines, updates tools, and provides ready environments for Linux, Windows, and macOS. In a workflow, that simplicity looks like this:

jobs:
  build:
    runs-on: windows-latest

The risky word is latest. It sounds like “give me the normal current platform”, but in practice it is a moving target. Today the label points to one runner image. After a rollout, it points to another. For a small lint job, nothing may change. For a build job that depends on Visual Studio, CMake, Android Command Line Tools, Xcode, code signing, or native dependencies, it is a real migration.

On the Windows side, GitHub is moving windows-latest and windows-2025 to an image with Visual Studio 2026. The official announcement specifically mentions changes around Visual Studio components, CMake, and Android Command Line Tools. On macOS, macos-latest will start pointing to macOS 26 instead of macOS 15. If your tests or builds care about Xcode, SDKs, notarization, simulator behavior, or native dependencies, test that before the mass migration reaches you.

Why it matters

CI usually does not break because an update exists. It breaks because there was a hidden dependency. The workflow never says “I require Visual Studio 2022”, but the build script behaves as if that version will always be there. Or YAML says macos-latest, while the signing step is quietly coupled to the toolchain from macOS 15.

These failures often look random:

  • the compiler suddenly cannot find a component;
  • CMake chooses a different generator;
  • browser or mobile tests fail during setup;
  • a .NET or C++ build picks up another SDK;
  • code signing works locally but fails in CI;
  • one run is green and the next is red during gradual rollout.

The worst version is finding this after the label has already started migrating. Then the team has to handle release pressure, GitHub Actions logs, and a new runner image at the same time. A small controlled migration is cheaper.

Illustration: where the risk lives

Think of runs-on as choosing a workbench for the job. The bench already has compilers, SDKs, package managers, and system libraries on it. When GitHub changes the runner image, the label may look the same, but some of the tools on that bench are different.

That means the audit should not treat all workflows equally. npm test on Ubuntu may be low risk. A Windows installer build, iOS build, Electron packaging, Playwright on system browsers, or C++ build with CMake is much more sensitive.

How to do it

1. Find every affected workflow

Start with a simple repository search:

rg -n "runs-on:.*(windows-latest|windows-2025|macos-latest)" .github/workflows

If you have many repositories, run this at organization level or at least across active services. Look beyond production deploy workflows. Scheduled builds, release jobs, mobile packaging, and manual workflow dispatch files matter too.

Create a short inventory:

  • workflow file;
  • job name;
  • current runs-on;
  • what the job does;
  • what hurts if the job fails.

2. Split jobs by risk

Not every job needs a manual migration on day one. Low risk means simple linters, unit tests without system dependencies, and jobs where runtime versions are explicitly installed through actions such as actions/setup-node.

Medium risk means browser tests, packaging, jobs with caches, Docker builds on Windows or macOS, and complex setup scripts.

High risk means .NET desktop, C++/CMake, Visual Studio workloads, Android builds on Windows, iOS/macOS signing, Xcode-sensitive steps, native modules, and any release job that blocks delivery to users.

3. Test Windows before rollout

GitHub provides the test label windows-2025-vs2026. The point is simple: you can run a job on the new image before windows-latest or windows-2025 start pointing there by default.

You do not have to change the main workflow immediately. Add a temporary manual job or a matrix:

name: runner-image-check

on:
  workflow_dispatch:

jobs:
  windows-build:
    strategy:
      fail-fast: false
      matrix:
        runner: [windows-2025, windows-2025-vs2026]
    runs-on: ${{ matrix.runner }}
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: ./build.ps1

Compare logs, duration, tool versions, and failures. If the job fails only on windows-2025-vs2026, that is not a “later” problem. It is a future incident arriving early in a controlled setting.

4. Test macOS 26 separately

The macOS logic is the same. macos-latest starts moving to macOS 26 on June 15, but macOS 26 images are already available through explicit labels. For Apple Silicon scenarios, use macos-26. For Intel, use macos-26-intel or the matching larger runner labels if your plan needs them.

A typical manual test looks like this:

jobs:
  macos-build:
    strategy:
      fail-fast: false
      matrix:
        runner: [macos-15, macos-26]
    runs-on: ${{ matrix.runner }}
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/ci-macos.sh

Watch Xcode selection, SDK paths, simulator boot, certificates, notarization, Homebrew packages, and native dependencies. If your workflow installs the required Xcode version or verifies tool versions explicitly, the risk is lower. If it trusts the default image, the risk is higher.

5. Decide: pinning or migration

There are two sane outcomes.

The first is migrating now. If the job passes on the new image, change the label deliberately or keep latest, but record that the check passed. This works well for teams that want to stay close to the current hosted runner stack.

The second is temporary pinning. If the job is critical and not ready, GitHub explicitly recommends windows-2022 for teams that need Visual Studio 2022, or macos-15 for teams that need to stay on macOS 15. That is fine. The problem is leaving a pin forever with no owner.

In a YAML comment or issue, record:

  • why the pin exists;
  • who owns it;
  • when you revisit migration;
  • which failure blocks the move.

6. Verify the first runs after the change

After merge, do not stop at one green run. Check several trigger types: pull request, push to main, release tag, scheduled workflow, and manual dispatch. Different triggers often expose different environment variables, secrets, cache keys, or artifact paths.

Also open Set up job in the GitHub Actions logs and inspect the Runner Image section. It shows which image the job actually used and links to the included software. That is better evidence than guessing from the label name.

Anti-patterns

  • leaving windows-latest or macos-latest in critical release jobs with no owner;
  • pinning everything automatically, even where the new image already works;
  • testing only one happy path and forgetting release or scheduled workflows;
  • ignoring Windows jobs because “we are a frontend team”;
  • moving the problem into a TODO comment without an issue, deadline, and owner;
  • treating a green unit test as proof that signing, packaging, and deploy are safe;
  • never reading the Runner Image section and guessing where the job actually ran.

Conclusion / Action plan

The June GitHub Actions migration does not need to become a crisis. It becomes a problem when a team does not know which workflows depend on moving -latest labels.

Practical plan for today:

  1. find every windows-latest, windows-2025, and macos-latest;
  2. split jobs by risk;
  3. run high-risk Windows jobs on windows-2025-vs2026;
  4. run high-risk macOS jobs on macos-26 or macos-26-intel;
  5. temporarily pin only the jobs that are genuinely not ready;
  6. after merge, inspect the Runner Image section in the first CI logs.

If you do not have time for a full migration now, do the minimum safe version: find critical release jobs and make an explicit decision for them. Everything else can be handled gradually, but your release pipeline should not be the first place that discovers Visual Studio 2026.

Official sources:

Quick checklist

  • Find every workflow using `windows-latest`, `windows-2025`, or `macos-latest`.
  • Mark jobs with native builds, mobile builds, code signing, browser tests, and .NET separately.
  • Run risky Windows jobs on `windows-2025-vs2026`.
  • Run risky macOS jobs on `macos-26` or `macos-26-intel`.
  • Decide where temporary pinning to `windows-2022` or `macos-15` is needed.
  • Save the rollback plan and inspect the first CI runs after rollout.

Prompt Pack: audit GitHub Actions runner images

Help prepare our GitHub Actions workflows for the June runner image migrations. Input data: - repository list or `.github/workflows/` snippets; - which labels are used in `runs-on`; - which jobs are release-critical; - whether there are Windows, macOS, mobile, .NET, native build, or browser test jobs; - whether the team can temporarily pin an OS label; - how much time remains before rollout. Return: 1. workflows using `windows-latest`, `windows-2025`, or `macos-latest`; 2. risk level for each job: low, medium, or high; 3. which jobs should be tested on `windows-2025-vs2026`, `macos-26`, or `macos-26-intel`; 4. where temporary pinning to `windows-2022` or `macos-15` makes sense; 5. a toolchain verification checklist; 6. a short rollback plan if CI breaks after rollout. Response format: risk table, concrete YAML changes, verification order, final recommendation.