Node 20 Removed from GitHub Actions: How to Migrate to Node 24
SOURCEGitHub
PUBLISHEDSeptember 23, 2026
LAYERTools
SIGNAL SCORE28/100
SXF / VERIFIED DEVELOPER CHANGELOG · UPDATED NOVEMBER 8, 2026
On September 23, 2026, GitHub ended Node 20 support as a JavaScript-action runtime and switched Actions execution to Node 24. The temporary ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION opt-out no longer works. Maintainers should release JavaScript actions with runs.using: node24; workflow owners should upgrade incompatible action versions. This is not the same as removing every ability to run Node 20 application code in a job.
IMPORTANT NOVEMBER CLARIFICATION
GitHub's runner team clarified on November 4 that node20 action metadata was being executed using Node 24 and that some runner packages still contained the old binary for compatibility. This is a temporary packaging detail, not supported runtime availability or a reason to keep old actions untested.
SXF TECHNICAL VIEW
The highest-risk migrations are self-hosted or old third-party actions with nonportable dependencies. Audit both the action runtime and the project runtime separately, upgrade supported dependencies, verify the runner and use repeatable acceptance tests before release.
SXF / ORIGINAL GITHUB ACTIONS MIGRATION GUIDE
Node 20 is no longer available in GitHub Actions: what to fix and what not to confuse.
Reviewed November 8, 2026
GitHub Actions retired Node 20 as a supported JavaScript-action runtime on September 23, 2026. Runners now execute JavaScript actions with Node 24, and the temporary override ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true has expired. If you're searching for “Node 20 is no longer available in GitHub Actions,” “GitHub Actions Node 24 migration” or “runs.using node24,” the first task is to determine whether your problem is in a JavaScript action, a workflow's Node application runtime, or a self-hosted runner. They're related but not identical. This guide explains the change, gives tested-by-source migration patterns, and proposes SXF's own acceptance checklist for avoiding avoidable CI outages. Read GitHub's official retirement notice.
FINAL CUTOFFSeptember 23, 2026Supported Node 20 action runtime retired
OLD OPT-OUTRemovedCannot force supported Node 20 behavior
SELF-HOSTED RUNNERSUpdate requiredVerify versions, OS and CPU architecture
What does “Node 20 is no longer available in GitHub Actions” actually mean?
GitHub's September 23, 2026 changelog states that JavaScript actions now use Node 24 on GitHub Actions runners, and that a temporary opt-out is no longer available. The change applies to github.com and GitHub with Data Residency. If you maintain an action, GitHub recommends changing its metadata runtime from node20 to node24 and publishing a new release. If you consume actions, upgrade to a current release that supports Node 24.
A JavaScript action is a packaged unit such as a checkout, setup or custom repository action. Its action.yml or action.yaml specifies the runtime under runs.using. The runner executes that JavaScript, including any configured pre- and post-job scripts. That is not the same setting as the Node version installed for your repository's npm test or node app.js command.
Was the Node 20 binary physically removed from every runner?
Do not infer that from the announcement's headline. In a November 4, 2026 GitHub runner-team clarification, an engineer said all Actions, including those whose metadata still declared node20, were being run under Node 24. The team had kept a Node 20 binary in runner packages temporarily for compatibility, with removal planned later in November. That packaging detail does not reinstate the supported Node 20 runtime or guarantee an old JavaScript action works unchanged.
It also explains a common source of confusion: an action can still contain runs.using: node20 in its metadata while being executed with Node 24. The actionable question is whether its code and dependencies are Node-24 compatible, not whether the string node20 happens to appear in a repository.
GitHub first described the deprecation on September 19, 2025 and subsequently revised its migration schedule. The official note lists June 16, 2026 as the start of Node 24 by default and September 23 as the cutoff for the temporary Node 20 override. The original article's notices include the date revisions; later comments should not be confused with a new grace period. Official timeline with editor's notes.
Date
Milestone
Practical impact
September 19, 2025
GitHub announced Node 20 deprecation
Action maintainers were told to prepare for Node 24
March 24, 2026
Node.js 20 last maintained release / EOL
Upstream security fixes no longer supplied for the release line
June 16, 2026
GitHub switched the default JS action runtime to Node 24
Temporary legacy-runtime override was still permitted
September 23, 2026
Node 20 action runtime retired
Temporary opt-out ended; Node 24 is required
November 4, 2026
Runner-team clarified physical binary retention
Some packages still included Node 20; actions nonetheless ran on Node 24
Separately, the Node.js release schedule reports Node 20 (Iron) reaching end of life after its March 24, 2026 update. Upstream EOL is a security-and-maintenance event; GitHub's September retirement is a specific CI infrastructure policy. They have related motivations but different operational effects.
Does actions/setup-node with node-version: 20 stop working?
Not automatically because of this particular GitHub announcement. The node-version input to actions/setup-node requests a Node executable for the steps in your job. The runs.using setting in the setup action's own metadata determines which Node executable runs the setup action. A Node-24-compatible setup action can, in principle, install another Node release for application scripts, subject to version availability and other constraints. Official actions/setup-node reference.
Where you see Node 20
What it controls
Recommended response
runs.using: node20 in action.yml
Built-in runtime for an individual JavaScript Action
Rebuild, retest and release for node24
node-version: '20' in setup-node
Node executable used by subsequent shell/run steps
Plan application migration to a supported LTS; test dependencies
node:20 in Dockerfile
Node image inside your container
Upgrade and test container and dependencies independently
Self-hosted runner's bundled runtime
Runner software that executes JavaScript actions
Update runner; verify Node 24, OS and architecture compatibility
Third-party action pinned to an old tag
Remote action's own code and metadata
Find current Node-24-compatible version and test it
Security caution: Keeping a Node 20 job for a compatibility test is not a recommendation to run EOL Node 20 in production. The Node.js EOL guidance explains that unmaintained lines no longer receive normal security fixes. Distinguish an unavoidable short-lived migration test from a maintained production build.
How to migrate a custom JavaScript GitHub Action from Node 20 to Node 24
If your repository publishes an action, inspect action.yml or action.yaml at its root or within .github/actions/. GitHub's action metadata syntax specifies the runs.using value. A minimal new configuration can be:
action.yml — JavaScript action runtime
name: "My JavaScript action"
description: "Run a checked JavaScript task"
runs:
using: "node24"
main: "dist/index.js"
The change is necessary but may not be sufficient. Modernize libraries that depend on older Node internals; confirm whether the action's bundled dist/index.js uses modern ESM or CJS behavior correctly; rebuild committed distribution output; and exercise any declared pre and post hooks. GitHub does not rebuild your committed action bundle just because you edit its metadata.
Find the action declaration. Check root action.yml / action.yaml and custom action directories. Identify Node 20 references in action metadata, not only workflow commands.
Change the runtime. Set runs.using to node24; verify documented main, pre and post file paths.
Update and rebuild. Install supported dependencies and regenerate any checked-in dist/ bundle using the project's build pipeline.
Run a local and CI test. Execute action unit tests and smoke-test the packaged action on a compatible runner; check initialization and post-job cleanup.
Publish a version. Tag and release the updated action, record any breaking changes and update workflows that consume the action.
Observe real runs. Check logs, outputs, network behavior, artifact uploads and expected permissions in the target environment.
Before/after: a safe metadata-only example
Before
runs:
using: "node20"
main: "dist/index.js"
After
runs:
using: "node24"
main: "dist/index.js"
This is an illustrative syntax change, not a guarantee of binary compatibility. Some old packages, native modules or bundled code require additional changes. The actual test should exercise the same inputs and outputs as production usage.
How to update workflows that consume Node 20-era actions
If your repository uses JavaScript actions, inspect files in .github/workflows/, especially lines beginning uses:. The referenced action may live in another repository, so looking only for node20 inside your own YAML cannot fully audit dependencies. Read each vendor's release notes and action metadata for the pinned version.
Example workflow with Node-24-compatible first-party actions
name: Node 24 smoke test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: "24"
cache: "npm"
- run: npm ci
- run: npm test
- run: npm run build --if-present
Important: These v5 references are illustrative known Node-24-compatible releases, not a claim that v5 remains the latest major in November 2026. Both actions/checkout and actions/setup-node document the move to Node 24 in v5, and their repositories document newer majors with additional changes. Select a current, reviewed version suitable for your runner; for sensitive workflows use verified immutable references or GitHub workflow dependency lockfiles where applicable.
This example deliberately uses node-version: "24" because the sample project is also being tested on a supported Node release. If your application still requires 20 temporarily, that is a separate application migration decision from the underlying action's own runtime. Testing applications on Node 24 and testing JavaScript actions under Node 24 should both be part of a complete migration.
How to audit action references quickly
Basic repository searches (not a full dependency audit)
# List referenced actions in workflow YAML
grep -RIn "uses:" .github/workflows/
# Find local JavaScript action runtime declarations
grep -RIn "using:.*node20" .github/actions/ 2>/dev/null || true
# Inspect the job runtime explicitly
node --version
npm --version
The second command only scans local actions under the standard folder. A third-party uses: vendor/action@tag dependency stores its action.yml in the vendor's repository, and a pinned SHA may refer to an older build. GitHub's secure-use reference explains dependency review, immutable pinning and supply-chain controls. Do not automatically update every major version without checking breaking changes.
Node 24 requirements for self-hosted GitHub Actions runners
The migration is especially consequential for self-hosted runners. GitHub's Node-24 migration notice says Node 24 is incompatible with macOS 13.4 and earlier and is not officially supported on ARM32. The September retirement applies to GitHub-hosted and supported self-hosted execution environments, but your team controls the software and OS image on self-hosted machines. GitHub's retirement announcement.
GitHub's official checkout and setup-node READMEs specify Actions Runner v2.327.1 or later for the Node-24-based v5 releases. Newer action features can require still newer runners; for example checkout v6 calls out an additional runner requirement when performing authenticated Git commands from a Docker container action. Do not stop at the minimum version for an earlier major if you choose a newer release.
Self-hosted check
What to verify
Common resolution
Runner application
Current supported version; at least compatible with the actions you use
Update runner software/image and retest
macOS host
Not macOS 13.4 or earlier for Node 24
Move to a supported macOS host
CPU architecture
Node 24 support; ARM32 is no longer supported in this transition
Move to a supported architecture
Docker and packages
Action dependencies, Linux container support and image compatibility
Rebuild containers and retest their hooks
Runner updates
Auto-update or manually managed image and service version
Follow documented runner upgrade cadence
GitHub's self-hosted runner documentation explains that hosts need ongoing runner updates to process new Actions features; older runner versions may stop receiving work. Do not treat fixing a JavaScript action as sufficient if the host operating system itself cannot run the required version.
Troubleshooting common GitHub Actions Node 20 / Node 24 errors
Symptom
Likely cause to investigate
Next check
A previously working action fails after September
Old action code or native dependency incompatible with Node 24
Read action changelog; update and test with the same inputs
Legacy opt-out has no effect
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION expired
Remove override and migrate action code/runtime
Self-hosted job fails before action starts
Runner binary too old or unsupported OS/CPU architecture
Check runner version, platform and required action version
Action metadata still says node20
Old published action tag or unreleased metadata
Choose compatible release and validate actual Node 24 behavior
Job still prints node -v as v20
Job runtime selected via setup-node or another PATH change
Inspect setup-node configuration; this is not the action runtime
Build fails on upgraded Node 24 project
Application dependency, native package or module compatibility
Run clean install and test project under supported Node version
Why the opt-out is not a rollback plan
Before September 23, GitHub offered ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true as a temporary migration escape hatch. GitHub now explicitly says this path is no longer available. Leaving the variable in a workflow can make troubleshooting harder because it implies a fallback that is no longer supported. The correct resolution is to maintain Node-24-compatible actions and supporting runners.
What about a warning that references Node 20?
A warning or outdated metadata does not by itself prove the actual running interpreter is Node 20. Inspect the action's version, runner logs and official compatibility notes. GitHub's November 4 clarification reports that actions declaring Node 20 were still being executed with Node 24. If a failure persists, reproduce it in a minimal workflow and isolate whether it occurs during setup, main execution, post-job cleanup or an application step. Runner-team clarification.
SXF analysis: this is a supply-chain migration, not just a version bump
Our editorial assessment: the biggest risk in the Node 20 retirement is not the text replacement node20 → node24. It is the chain of dependencies behind a CI job. Workflows load actions from different repositories, often pinned to majors or commits. A GitHub-hosted runner can move to Node 24 without every third-party action maintainer having tested the change. At the same time, older self-hosted runner images can make a supported action unusable. Successful migration requires evidence at the workflow, action, runner and application levels.
That gives security teams a second opportunity: audit the trust and permissions of every action while updating it. Check whether the action has access to repository write permissions or production secrets, whether a release tag can be changed, and whether a forked pull request can influence a privileged workflow. GitHub's secure-use guidance recommends dependency lockfiles for verified and transitive action sources, or full-length SHA pinning where lockfiles are not in use. This is an independent concern from Node compatibility, but migration work is an efficient moment to address both.
Original SXF seven-gate migration acceptance framework
Gate
Review question
Suggested evidence
1 · Inventory
Have all first- and third-party JavaScript actions been listed?
Workflow references and dependency graph
2 · Runtime
Does each custom/published action support Node 24?
Metadata, packaged bundle and version release note
3 · Host support
Can every required runner execute the chosen action?
Version, OS and architecture inventory
4 · Functional test
Do setup, main, post and actual job commands work?
Clean CI run, tests, generated artifacts
5 · Security
Are permissions, action supply chain and secrets bounded?
Token scopes, action locks/pins and review
6 · Rollback readiness
Could a bad deployment be contained without relying on old Node 20?
Known-good Node-24-compatible release and change plan
7 · Ownership
Who watches failures and reviews updates over time?
Maintainer, alerting and update policy
This seven-gate SXF framework is original editorial guidance for evaluating a CI migration, not a prescribed GitHub compliance standard or a claim that SXF executed these tests on your repository. It measures practical readiness rather than counting updated YAML strings. A migration that passes all seven gates should have a defensible evidence trail; it still cannot guarantee that every future dependency change will be safe.
A migration decision tree for three kinds of maintainers
IF YOU MAINTAIN AN ACTION
Release a Node-24-compatible package
Change metadata, upgrade dependencies, rebuild the distribution, exercise hooks and publish a tested version.
IF YOU OWN A WORKFLOW
Review upstream action versions
Check referenced actions, upgrade supported releases and validate actual behavior, then protect the dependency chain.
IF YOU OPERATE SELF-HOSTED RUNNERS
Fix the environment first
Upgrade the runner and unsupported operating systems or CPU architecture before troubleshooting individual action code.
Frequently asked questions: Node 20 removal from GitHub Actions
When did GitHub Actions stop supporting Node 20 for JavaScript actions?
September 23, 2026. GitHub's final retirement notice says JavaScript actions now run on Node 24 and the temporary opt-out is unavailable.
Does a workflow using node-version: 20 automatically fail?
No. That setup-node input selects a job's application runtime, distinct from the runtime used to run the JavaScript action itself. Node 20 remains end-of-life and should be migrated for security.
What is the action.yml migration?
For a custom JavaScript action, change runs.using to node24, rebuild any bundled JavaScript, test setup/main/post hooks and publish an updated release.
Can I use ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION?
No. GitHub states the temporary override is no longer available after September 23.
Can a GitHub action with runs.using: node20 still execute?
GitHub clarified in November that the runner executes even legacy-declared actions with Node 24. That does not guarantee their code remains compatible or that the Node 20 runtime is supported.
Which checkout and setup-node releases support Node 24?
Both official actions document the move in their v5 majors, with newer majors containing additional updates. Pick a release compatible with your runner and test before rollout.
What is the minimum self-hosted runner version?
For checkout v5 and setup-node v5, GitHub specifies v2.327.1 or later. Other actions and later features may require newer versions.
Which operating systems and architectures are affected?
GitHub says Node 24 is incompatible with macOS 13.4 and older and does not officially support ARM32, so those self-hosted configurations are no longer supported in this change.
Why did GitHub move away from Node 20?
Node 20 reached upstream end of life in March 2026. Maintaining an unsupported runtime increases security and dependency risks; GitHub moved action execution to supported Node 24.
How should a team verify its migration?
Audit all action dependencies and runner platforms, test the packaged action under Node 24, run real workflow smoke tests, inspect logs and protect privileged workflow permissions.
Official sources, verification notes and editorial disclosure
Source review: November 8, 2026. GitHub's September 23 announcement is the primary news source; the earlier schedule explains the cutoff, and the November 4 GitHub staff comment clarifies temporary binary packaging. This article distinguishes officially supported JavaScript-action execution from application Node versions installed in workflow steps. The SXF seven-gate process is original analysis, not a claim of firsthand tests or a certification by GitHub. Example YAML and shell commands are educational and must be tested in each repository.