GitHub Actions removed Node 20 from every runner on September 23, 2026, and there's no compatibility switch left to flip. Node 24 is now the only runtime GitHub supports for JavaScript actions, according to GitHub's changelog post announcing the removal. Any workflow still calling an action whose action.yml declares runs.using: node20 has no runtime left to run on: the changelog calls this the final notification, and the job cannot execute without Node 24.
What changed on September 23, 2026
Node 20 is gone from GitHub Actions runners, full stop. Before this date, an action built for Node 20 would still run, sometimes with a deprecation warning, sometimes silently if a team had flipped the escape hatch. That's over. GitHub's runners execute JavaScript actions on Node 24 exclusively now, and nothing in a workflow file or environment variable brings Node 20 back.
This didn't arrive without warning. GitHub flagged the change more than a year out, then flipped the runner default months before actually pulling Node 20. Teams that treated the September 2025 notice as a someday problem now have a today problem: the removal already happened.
Why your workflow is failing right now
Four things break, and they break for different reasons.
An action still declaring runs.using: node20 in its action.yml used to still execute, sometimes with a warning, sometimes because a workflow had the unsecure-node-version escape hatch flipped. Now it doesn't run at all. The fix is binary: either the action's maintainer ships a release with runs.using: node24, or the consuming workflow moves to a version tag that already has it.
Self-hosted runners on macOS 13.4 or earlier can't run Node 24, and no workflow YAML edit changes that. The runner's operating system has to move first.
Self-hosted runners on ARM32 fail the same way. That architecture can't run Node 24, so any JS action on that runner keeps failing until the runner itself changes.
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true no longer does anything. Whoever set it after the 2025 deprecation notice, or after the June 2026 default switch, just lost the last workaround. GitHub disabled the variable as part of the same September 23 change.
None of these four resolve independently. A team can fix its own actions and still get taken down by a runner fleet nobody's audited in two years.
How to fix your GitHub Actions pipeline
1. Find every action still declaring node20
Grep across every repo your org owns for runs.using: node20 in action.yml files, and separately check every workflow file for pinned action versions, @v3, @v2, a specific SHA, that predate a Node 24 release. Every action's action.yml sets runs.using to declare its runtime; GitHub's documentation on writing JavaScript action metadata lists that field as required, with node20 and node24 as the only accepted values, though only the latter runs anywhere now. A single-repo check tells you almost nothing on a real fleet: the point of this step is coverage across every repo that runs a workflow, since checking only the one that broke first will miss the others quietly failing the same way.
2. Update a custom action you maintain to node24
If your org owns the action, the change itself is small: edit runs.using to node24 in action.yml, confirm the action's code runs clean on Node 24 (module resolution and native dependencies are the usual snags), and cut a release. The removal notice's maintainer instructions say to publish that release as soon as possible. Editing the file locally doesn't help a consumer until a new version tag ships with it.
3. Bump third-party actions to a Node 24-compatible release
For actions you consume but don't own, the fix lives in the workflow file, not the action's source. Update the pinned version, say @v3 to @v4, to whichever release actually declares runs.using: node24. Bumping a version number without checking the target release's action.yml is a common way to think you've fixed this and still be broken.
4. Check self-hosted runner OS and architecture
Pull the OS version and architecture for every self-hosted runner registered to the org, not just the ones that already failed. macOS 13.4 or earlier and ARM32 architecture both need a runner-level upgrade before any JS action executes there again. GitHub-hosted runners don't have this problem; they're already on Node 24.
5. Confirm the fix ran clean
Re-run the workflows that failed and check the job logs for the runner's Node version, not just a green checkmark. A workflow can pass because a conditional skipped the failing step or a cache hit short-circuited it, not because the action actually ran clean on Node 24. Treat this the same way you'd treat auditing your CI/CD pipeline's privilege boundaries: a pipeline that looks green on the surface can still be hiding a gap nobody checked for directly.
The timeline, in full
Three dates, three separate changes.
September 19, 2025: GitHub published GitHub's September 2025 deprecation notice, stating that Node 24 would become the runner default starting June 16, 2026, and that the unsecure-node-version variable would work as a temporary bridge in the meantime. The same notice states that Node 20 reaches end of life in April 2026, GitHub's own wording, not a figure pulled from Node.js's own release page.
June 16, 2026: Node 24 became the default runtime on GitHub Actions runners. Actions still on Node 20 kept working past this date only because the opt-out variable was still live.
September 23, 2026: Node 20 was pulled entirely, and the opt-out variable stopped functioning. That's the point where a team without a fix in place actually goes down.
A GitHub Community discussion thread about the removal timeline shows how much confusion sat in that gap. One commenter asked whether there was a specific date set for the final cutoff, and had to be told GitHub hadn't announced one yet, months after the deprecation notice went out and months before the removal actually happened. The three-date sequence above is the answer that thread was missing.
Node 20, the Iron release line, carries an end-of-life status on Node.js's own release table, separate from anything GitHub Actions does on its own schedule. That table only shows when the version was first released and when the page itself was last updated, not a labeled end-of-life date, so the April 2026 figure above comes from GitHub's changelog, not from Node.js directly.
Teams auditing more than one platform upgrade this quarter
Node 20's removal isn't the only forced change landing on infrastructure teams this cycle. Swift 6.4 shipped a default build-system swap that breaks CI without warning, buried in a release note most teams skim past. Kubernetes 1.37 carries a hard-stop deprecation that kills the process outright if a removed flag survives anywhere in a node's config. Both share the same shape as this one: a changelog line that reads as routine until it takes a pipeline down.
If nobody on the team currently owns this kind of maintenance full time, it's worth asking whether the engineer who owns CI/CD pipeline maintenance is a role you're missing rather than a task you're distributing across whoever's free that sprint.
FAQ
Is there still a way to opt back into Node 20?
No. ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION was the only opt-out, and GitHub disabled it as part of the same September 23, 2026 change that removed Node 20 itself. There's no environment variable, flag, or setting left that brings it back.
What happens to workflows that never update?
They stay broken. A workflow calling an action that declares runs.using: node20 keeps failing on every run until either the action ships a Node 24 release or the workflow moves to a different action version. Nothing resolves on its own.
Does this affect GitHub-hosted runners, self-hosted runners, or both?
Both, but differently. GitHub-hosted runners already run Node 24, so the fix there is entirely about which actions your workflows call. Self-hosted runners carry the extra requirement that the runner's own OS and architecture support Node 24, which is why macOS 13.4-and-earlier and ARM32 runners are locked out until the runner itself changes.
When does Node 20 itself reach end of life outside of GitHub Actions?
GitHub's own September 2025 deprecation notice states that Node 20 reaches end of life in April 2026. Node.js's release table lists Node 20, the Iron line, with an end-of-life status but doesn't print that date directly on the page, so the April 2026 figure traces back to GitHub's changelog rather than to Node.js's own site.
