# GitHub Actions deprecations: what breaks, when, and the fix

> GitHub Actions deprecations with the date each one takes effect: runner images, moving labels, Node 20 actions and workflow commands, read 2026-09-20.

Source: https://latchkey.dev/learn/ci-explained/github-actions-deprecations-tracker  
Updated: 2026-09-20

GitHub Actions deprecations arrive as a warning, spend a few months as slower queues and scheduled brownouts, and end as a job that terminates with an error. This page tracks the ones in flight with the date each takes effect, read from the announcements on 2026-09-20.

The distinction that matters on this page is between a deprecation and a retirement. A deprecation is the announcement plus the warnings: your workflow still runs, and GitHub tells you it will not forever. A retirement is the date the label or the runtime stops working, and on that date a job naming it terminates with an error rather than degrading.

Between those two dates GitHub usually runs brownouts, which are scheduled windows where jobs using the deprecated thing fail on purpose so that a team with no dashboard finds out anyway. They are the most useful signal in the whole process and the one most often mistaken for an outage.

## How to read this page, and how often it is wrong

Everything below was read from its source on 2026-09-20 and carries a link so you can check it rather than trust this page. It is refreshed monthly by rule, because the announcements arrive continuously and a tracker that is six weeks stale is worse than no tracker: it gives a team a reason not to look.

One thing to internalize about the schedule: GitHub maintains "the latest two stable versions of any given OS version", which is the sentence that appears in every image deprecation announcement. That is the rule generating all of these dates, so a new Ubuntu or macOS release going generally available is also the clock starting on the oldest one.

## Runner images

A retired image label is a hard failure, not a fallback. Workflows naming one are terminated with an error.

| Image label | Deprecation begins | Fully unsupported | Move to |
| --- | --- | --- | --- |
| `ubuntu-22.04`, `ubuntu-22.04-arm` | 17 September 2026 | 17 April 2027 | `ubuntu-24.04`, `ubuntu-26.04` or `ubuntu-latest` ([#14254](https://github.com/actions/runner-images/issues/14254)) |
| `macos-14`, `macos-14-large`, `macos-14-xlarge` | 6 July 2026 | 2 November 2026 | `macos-15`, `macos-26` or `macos-latest` ([#13518](https://github.com/actions/runner-images/issues/13518)) |
| `macos-13` | 22 September 2025 | 4 December 2025 | Already retired ([#13046](https://github.com/actions/runner-images/issues/13046)) |
| `ubuntu-20.04` | 1 February 2025 | 15 April 2025 | Already retired ([#11101](https://github.com/actions/runner-images/issues/11101)) |
| `windows-2019` | 1 June 2025 | 30 June 2025 | Already retired ([#12045](https://github.com/actions/runner-images/issues/12045)) |
| `macos-12` | 7 October 2024 | 3 December 2024 | Already retired ([#10721](https://github.com/actions/runner-images/issues/10721)) |

> The `ubuntu-22.04` brownouts are scheduled for 23 and 30 March and 6 and 13 April 2027, each from 14:00 UTC. A job that fails only inside one of those windows is not flaky.

## Labels that move under you

A `-latest` label is not a pin and was never meant to be one. It points at the newest image GitHub considers generally available, and it is migrated on a schedule that is announced but easy to miss, because nothing in your workflow file changes when it happens.

`ubuntu-latest` is mid-migration right now. The announcement of 17 September 2026 says the move from Ubuntu 24.04 to 26.04 begins on 19 October 2026 and is planned to complete by 19 November 2026, rolled out over several weeks. The kernel goes from 6.17 to 7.0 with it, and workflows depending on a package version, system library, compiler or prebuilt binary from 24.04 are the ones that notice. `macos-latest` already moved to `macos-26` between 15 June and 15 July 2026, and `windows-11-arm` starts moving to the Visual Studio 2026 image tomorrow, 21 September 2026, completing by the 30th.

The fix is a decision rather than a command. If a version matters to your build, name it: `runs-on: ubuntu-24.04`. If it does not, `ubuntu-latest` is correct and the migration is somebody else's problem. What does not work is `ubuntu-latest` plus an assumption about which release it is.

```.github/workflows/ci.yml
# Moves without asking, over one to two months
runs-on: ubuntu-latest

# Pins the OS release. The image build underneath still rolls forward
runs-on: ubuntu-24.04
```

## Actions, runtimes and workflow commands

These deprecations are about what your workflow calls rather than what it runs on. Two of them have no removal date at all, which is its own kind of trap: the warning stays survivable until suddenly it is not.

| What is deprecated | Status on 2026-09-20 | The fix |
| --- | --- | --- |
| Actions declaring `using: node20` | Warning only. An end-of-job annotation says the actions "are running on Node.js 20 and may not work as expected". No removal date announced | Move to `node24`, the current runtime, or upgrade the action. See [actions/runner#4295](https://github.com/actions/runner/issues/4295) |
| `set-output` and `save-state` workflow commands | Deprecated 11 October 2022. Removal was planned for 1 June 2023 and postponed on 24 July 2023 over usage. Still functional | Write to the `$GITHUB_OUTPUT` and `$GITHUB_STATE` files |
| `actions/upload-artifact@v3` and `download-artifact@v3` | Closed down 30 January 2025. v1 and v2 went earlier | v7 of upload-artifact and v8 of download-artifact are current. v4 introduced the breaking changes |
| Older `actions/cache` majors | `v1` and `v2` fail: the cache service rewrite landed 1 February 2025 and the legacy service was sunset the same day ([README](https://github.com/actions/cache#readme)) | v6 is current. v5 and above run on Node 24 and need runner 2.327.1 or newer |
| Go 1.23 and earlier in the toolcache | Removed from the images from 22 June 2026. 1.24, 1.25 and 1.26 remain ([#14237](https://github.com/actions/runner-images/issues/14237)) | Nothing, if you use `actions/setup-go`: it downloads what the toolcache no longer holds, more slowly |
| Android NDK 28 on the images | Removed from 1 October 2026, NDK 30 added. The installed set becomes 27, 29 and 30 and the default stays 27 ([#14745](https://github.com/actions/runner-images/issues/14745)) | Nothing, unless a workflow names NDK 28 explicitly. The default `$ANDROID_NDK` is unchanged, so only a pinned 28 breaks |

## The current majors, read today

Half of staying ahead of deprecations is simply not being three majors behind. These were read from the GitHub API on 2026-09-20 and are the current releases of the actions most workflows use. If your workflow names a lower major, nothing is broken today and the gap is where the next forced migration will find you.

Pin to the major while you are reading warnings, and to a full commit SHA for anything outside your organization once you are not. [GitHub Actions security](/learn/ci-explained/ci-security-github-actions) covers why the SHA matters and what it costs.

```.github/workflows/ci.yml
- uses: actions/checkout@v7          # v7.0.1, 20 July 2026
- uses: actions/setup-node@v7        # v7.0.0, 14 July 2026
- uses: actions/cache@v6             # v6.1.0, 26 June 2026
- uses: actions/upload-artifact@v7   # v7.0.1, 10 April 2026
- uses: actions/download-artifact@v8 # v8.0.1, 11 March 2026
- uses: actions/setup-python@v7      # v7.0.0, 20 July 2026
- uses: actions/setup-java@v6        # v6.0.1, 9 September 2026
```

## How to stay ahead without reading changelogs

Deprecation warnings appear in the run log and in the job summary, and they are the cheapest signal available because they arrive months early and name the thing. Treat them as work rather than as decoration: one a month, in the same place you handle dependency updates, is enough to never be caught by a retirement.

Dependabot handles the action versions if you let it, including SHA pins, which it updates the same way it updates package versions. What it does not cover is the runner image labels, because those are not dependencies in any file it reads. Those need either a `-latest` label and a tolerance for movement, or a pinned label and a calendar entry, and the table above is the calendar.

The last piece is knowing what you actually use. A quick search across your workflows for `runs-on:` and for `uses:` majors takes a minute and usually finds a repository nobody has opened since 2024, which is exactly the one that will fail during a brownout.

```Terminal
# Every runner label and action major in the organization
gh search code --owner ORG --filename "*.yml" "runs-on:" --limit 200
grep -rhoE "uses: [a-z0-9-]+/[a-z0-9-]+@v[0-9]+" .github/workflows | sort | uniq -c | sort -rn
```

## FAQ

### Is actions/cache v3 deprecated in 2026?

Not in the sense that it stops working. When the cache service was rewritten and the legacy service sunset on 1 February 2025, the versions that fail are `v1` and `v2`; the README told people to upgrade to `v4` or `v3`, so v3 is on the supported side of that line. It is four majors behind, which is the real argument for moving: `v6` is current as of 26 June 2026, and `v5` and above run on Node 24 and need Actions runner 2.327.1 or newer, which matters if you self-host.

### When do the ubuntu-22.04 runner images stop working?

Deprecation began on 17 September 2026 and the images are fully unsupported from 17 April 2027 for both GitHub Actions and Azure DevOps. Between those dates expect longer queues at peak and four scheduled brownouts in late March and early April 2027 where jobs on that label fail deliberately. Move to `ubuntu-24.04` or `ubuntu-26.04`.

### When does ubuntu-latest become Ubuntu 26.04?

The rollout begins on 19 October 2026 and GitHub plans to complete it by 19 November 2026, spread over several weeks so that not every repository moves at once. The kernel changes from 6.17 to 7.0 alongside the userspace. If your build depends on a specific package version, compiler or prebuilt binary from 24.04, pin `runs-on: ubuntu-24.04` before October.

### Why does my workflow warn that actions are running on Node.js 20?

Because an action in the run declares `using: node20` in its metadata and the runner now annotates that at the end of the job. It is a warning with no announced removal date, and the action itself is what has to change, not your workflow. Upgrading the action to a version built for `node24` clears it; actions/runner#4295 documents the annotation, including a case where it fires inaccurately.

## References

- [actions/runner-images#14254: Ubuntu 22 deprecation and retirement dates (read 2026-09-20)](https://github.com/actions/runner-images/issues/14254)
- [actions/runner-images#14748: ubuntu-latest moves to Ubuntu 26.04 (read 2026-09-20)](https://github.com/actions/runner-images/issues/14748)
- [actions/runner-images#13518: macOS 14 deprecation and retirement dates (read 2026-09-20)](https://github.com/actions/runner-images/issues/13518)
- [GitHub Changelog: deprecating save-state and set-output (read 2026-09-20)](https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/)
- [GitHub Changelog: v3 of the artifact actions closed down (read 2026-09-20)](https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/)

---

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
