The macos-14 runner image retires on November 2, 2026, and the first of eight scheduled brownouts starts on October 5 at 14:00 UTC. GitHub's retirement announcement covers three labels: macos-14, macos-14-large and macos-14-xlarge. During a brownout, jobs on those labels fail on purpose. After November 2, they have nowhere to run. If your iOS or macOS pipeline still says macos-14 anywhere, the first red build is days away, and the fix is a label change plus a decision about which Xcode you actually want.
This is one entry in a running list of platform and language changes that break builds, and it's the most mechanical of them. The part that takes thought is Xcode.
What GitHub is retiring and when
Deprecation of the image began on July 6, 2026, according to the tracking issue in the runner-images repo, which lists November 2, 2026 as the date it becomes unsupported. The issue's stated policy is that GitHub Actions maintains the latest two stable versions of any given OS version. macos-14 is now behind macos-15 and macos-26.
Three labels go away. macos-14 is the standard Apple silicon runner, macos-14-xlarge is the larger Apple silicon runner, and macos-14-large is the Intel one.
Each brownout runs 10 hours, from 14:00 UTC to 00:00 UTC the next day. The tracking issue says jobs on those three labels fail during those windows. Outside them, jobs run normally, with one caveat: the changelog says GitHub may reduce macOS 14 runner capacity, which could mean longer queue times. Don't read a slow queue on a quiet day as a glitch.
| Brownout | Starts (UTC) | Ends (UTC) |
|---|---|---|
| 1 | October 5, 14:00 | October 6, 00:00 |
| 2 | October 12, 14:00 | October 13, 00:00 |
| 3 | October 16, 14:00 | October 17, 00:00 |
| 4 | October 19, 14:00 | October 20, 00:00 |
| 5 | October 23, 14:00 | October 24, 00:00 |
| 6 | October 26, 14:00 | October 27, 00:00 |
| 7 | October 29, 14:00 | October 30, 00:00 |
| 8 | October 30, 14:00 | October 31, 00:00 |
The last two windows run on consecutive days, with only a 14-hour gap between them (00:00 to 14:00 UTC on October 30). If you're planning a release for the end of October, assume nothing on macos-14 builds in either window.
What changes when you leave macos-14
The label swap is trivial. The toolchain swap isn't. Per the image readmes as of October 4, 2026 (image versions change, so check the live pages before you decide), the three images differ like this:
| Image | OS | Default Xcode | Other Xcode versions | Apple silicon labels |
|---|---|---|---|---|
| macos-14 | 14.8.9 | 15.4 | 16.2, 16.1, 15.3, 15.2, 15.1, 15.0.1 | macos-14, macos-14-xlarge |
| macos-15 | 15.7.9 | 16.4 | 26.3, 26.2, 26.1.1, 26.0.1, 16.3, 16.2, 16.1, 16.0 | macos-15, macos-15-xlarge |
| macos-26 | 26.6.2 | 26.6 | 26.0.1 through 26.5 | macos-latest, macos-26, macos-26-xlarge |
The sources are the readmes for the macos-14 image, the macos-15 image and the macos-26 image.
The consequence is the one most teams will miss. macos-14's default is Xcode 15.4, and its list is mostly 15.x. The macos-15 list starts at 16.0. There's no Xcode 15.x on it. A job that relied on the default Xcode jumps to 16.4 on macos-15 or 26.6 on macos-26, and a job that pinned 15.3 or 15.4 has nothing to pin to. The macos-26 image carries only Xcode 26.x, so a job pinned to any 16.x version has nothing to pin to there either.
macos-latest already points at macos-26, not macos-15. If you're on macos-latest, this retirement doesn't affect you, but your default Xcode is already 26.6.
For Intel jobs, the tracking issue maps macos-14-large to macos-latest-large or macos-15-large. GitHub's larger runners reference lists macos-15-large and macos-26-large among the Intel labels, and macos-15-xlarge and macos-26-xlarge on Apple silicon. Intel is a dead end for anyone planning on new Xcode releases: Xcode 27 is Apple silicon only, as we covered in our Xcode 27 release notes breakdown. Moving an Intel job to macos-15-large buys time, not a future.
How to migrate off macos-14 runners
Seven steps, in the order a lead should run them. In our experience steps 1 to 4 are quick, and step 5 is where the real time goes.
1. Find every macos-14 reference
Search every workflow file for runs-on lines containing macos-14, and search for macos-14-large and macos-14-xlarge separately. Don't stop at .github/workflows. Reusable workflows, matrix os: lists, and composite actions can all carry the label, and the repo still on macos-14 is often one nobody has touched in a while.
2. Record which Xcode each job really uses
Search for xcode-select, DEVELOPER_DIR, and any step that sets the Xcode version before the build. Add xcodebuild -version to jobs that don't print it, so the log says what ran. A job with no explicit selection is using the image default: 15.4 today, 16.4 on macos-15, 26.6 on macos-26. That job is the one that will change behaviour without any edit to its Xcode handling.
3. Pick the target label per job
Choose macos-15 when you want the smallest toolchain change, since it keeps you on Xcode 16.x. Choose macos-latest or macos-26 when you want the current Xcode and are ready to deal with it. Move macos-14-large to macos-15-large, and macos-14-xlarge to macos-15-xlarge or macos-26-xlarge. Larger runners need a valid credit card on file and a spending limit above zero, per the larger runners documentation linked above. Check that before a release branch is blocked on a billing setting.
4. Change the label and pin Xcode explicitly
Edit the label, then stop relying on the default. Select the Xcode version your job needs from the list in the target image's readme, and keep that selection in the workflow so the next image update doesn't move it. The xcodebuild -version step makes the selected version visible in every log.
Each Xcode sits at a versioned path on the image, such as /Applications/Xcode_16.4.app on macos-15. Check the exact name in the target image's readme, then select it:
# before
jobs:
build:
runs-on: macos-14# after
jobs:
build:
runs-on: macos-15
steps:
- run: sudo xcode-select -s /Applications/Xcode_16.4.app
- run: xcodebuild -versionThe second block is the shape of the change, not a full pipeline. Keep your existing steps and put the Xcode selection and the version check at the top.
5. Run on a branch before 14:00 UTC on October 5 (or the next window)
Push the label change to a branch and run the whole pipeline, including the slow jobs nobody runs on every commit. Expect differences in simulator runtimes, code signing, and SwiftPM resolution. If you're also moving to a new Xcode, remember that Swift 6.4 makes Swift Build the default in SwiftPM (Swift 6.4's new default build system), which will matter once your toolchain reaches it. Separate the two changes if you can: label first, Xcode jump second, so a red build has one suspect.
6. Decide on self-hosted or larger runners only for what must stay
If a job needs a toolchain that no GitHub-hosted image offers, such as a pinned Xcode 15.x, the options are a self-hosted Mac or a larger runner on a newer image that happens to carry what you need. Self-hosted trades GitHub's image maintenance for your own: you patch the OS, you update Xcode, and you keep the runner software above GitHub's version floor, which the self-hosted runner minimum version page covers. The Node 20 removal already forced that on macOS 13.4 and older. Keep this list short. Every job you move to your own hardware is one you maintain from now on.
7. Use the brownout as a test
A brownout fails jobs with an error, which makes it a free rehearsal. Leave one canary job on macos-14 in a non-blocking workflow so you see exactly what failure looks like in your logs and notifications. Anything still on macos-14 in a required check will turn your release branch red during the window. Delete the canary after November 2.
What to do if a job already failed during a brownout
The failures are intentional, and they're recognisable. The job fails at the runner level rather than in a build step, and the timestamp falls inside one of the windows in the table above. A failure at 09:00 UTC on a brownout day is a different problem.
You have two options. If the failed job was a one-off, re-running it after the window ends will work, provided GitHub's reduced capacity doesn't leave it queued for long. That buys you one window, not a fix. If the job is a required check on a release branch, migrate now. Waiting for each window to pass and re-running is a process that fails permanently on November 2.
FAQ
Does macos-latest already point at macos-26?
Yes. The runner-images readme lists macos-latest alongside macos-26 for the Apple silicon image. A workflow on macos-latest isn't affected by the macos-14 retirement.
Will my macos-14-large Intel jobs have a replacement?
Yes. The tracking issue maps macos-14-large to macos-latest-large or macos-15-large. Treat it as a stopgap. Xcode 27 is Apple silicon only, so Intel jobs have a limited runway for new toolchains.
Do I need to change anything for self-hosted runners?
Not for this notice. The announcement lists only GitHub-hosted labels (macos-14, macos-14-large and macos-14-xlarge), so a self-hosted Mac isn't covered by the retirement. Other changes can still reach it, such as the runner version floor mentioned in step 6.
How long are the brownouts?
Ten hours each, from 14:00 UTC to 00:00 UTC the next day. There are eight, between October 5 and October 31, 2026, and the last two fall on October 29 and 30.
