GitHub Actions: "Node.js 20 is deprecated" warning
One or more actions in the job declare Node 20 as their runtime. GitHub removed Node 20 from its runners on September 23, 2026, so the runner ran them on Node 24 anyway and left this warning. The job did not fail because of it. To make it go away, move each named action to a version built for Node 24.
What it looks like
The annotation on a public run on October 30, 2026 (runner 2.338.2):
Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
- The list names each action exactly as the workflow wrote it: a tag such as
actions/checkout@v4, or a full commit SHA when the workflow pins one. - Before June 16, 2026 the same actions still ran on Node 20 and the warning read "Node.js 20 actions are deprecated. The following actions are running on Node.js 20 and may not work as expected".
What it changes now
- Nothing you can switch back. GitHub's changelog of September 23, 2026: "Runners now use Node 24 for JavaScript actions. The temporary
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSIONopt-out is no longer available."FORCE_JAVASCRIPT_ACTIONS_TO_NODE24is no longer needed either. - The warning is about the runtime of the actions, not the Node your project builds with.
actions/setup-nodewithnode-version: 20still installs Node 20 for your own steps (20.20.2 is the last release; Node 20 reached end of life in April 2026). The Ubuntu images preinstall Node 22 and 24 only. - Self-hosted runners on macOS 13.4 or earlier, or on 32-bit ARM, are no longer supported, because Node 24 does not run there.
Finding the line that pins it
- List every action reference in the repository:
grep -rhoE 'uses: *[^ ]+@[^ ]+' .github/ | sort | uniq -c | sort -rn
- For a SHA pin, find which tag it is, then check the runtime of any version:
gh api "repos/actions/checkout/tags?per_page=100" --jq '.[] | select(.commit.sha | startswith("08eba0b2")) | .name' gh api "repos/actions/cache/contents/action.yml?ref=v4" --jq .content | base64 -d | grep using - If no file in your repository has the version the warning names, it comes from somewhere you call. A reusable workflow from another repository keeps its own pins, so only that repository can move them (Morrison-Lab/gha #1405). A composite action can wrap an old one:
codecov/codecov-actionv5 runsactions/github-scriptv7.0.1 inside, which targets Node 20, while v6 runs github-script v8. - A floating major tag is not always the newest release:
pnpm/action-setup@v4still points at a Node 20 build, although v4.4.0 runs on Node 24.
The first Node 24 version of the actions it names most
From each action's action.yml at its tags on November 3, 2026, in order of how many public issues and pull requests since October 1 mention the action together with this warning:
actions/checkout: v5 (latest v7.0.1)actions/setup-node: v5 (latest v7.1.0)actions/upload-artifact: v6 (latest v7.0.2)actions/setup-python: v6 (latest v7.1.0)actions/cache: v5 (latest v6.1.0)actions/download-artifact: v7 (latest v8.0.2)actions/github-script: v8 (latest v9.0.0)gradle/actions/setup-gradle: v5 (latest v6.4.1)pnpm/action-setup: v5, or v4.4.0 exactly (latest v6.1.0)codecov/codecov-action: v6 (latest v7.1.1)actions/deploy-pages: v5;actions/configure-pages: v6;actions/upload-pages-artifact: v5, which uploads with upload-artifact v7actions/setup-java: v5;actions/setup-go: v6;actions/setup-dotnet: v5docker/build-push-action: v7;docker/setup-buildx-action,docker/login-actionanddocker/setup-qemu-action: v4;docker/metadata-action: v6softprops/action-gh-release: v3;actions/labeler: v6;github/codeql-action: v4;peter-evans/create-pull-request: v8;aws-actions/configure-aws-credentials: v6;actions/stale: v10
A new major version can change inputs or defaults, so read its release notes before moving. For example, actions/download-artifact v8 fails on a hash mismatch by default, where v7 only warned.
To get these updates as pull requests from now on, let Dependabot watch the workflow files:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
When the job did fail
Most Node 20 actions keep working on Node 24, so a red job usually has another cause; look at the error annotation, not this warning. In October two projects suspected the forced runtime and moved to a Node 24 release: actions/labeler@v4 failing with "Parameter token or opts.auth is required" (semantic-fleet #105), and a post-job step of DeterminateSystems/magic-nix-cache-action@v8 crashing after the job's own work had passed (some-ui #2362).
If you maintain a JavaScript action, set runs.using: node24 in its action.yml and publish a new release, ideally a new major version, so that users who follow the major tag get it.
See failed jobs from IntelliJ IDEA
Pipeline Inbox for GitHub Actions Workflows, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, lists the runs of all your repositories in an IDE tool window, with their jobs and steps, and your current branch's runs are in the status bar. Reading is free; re-running failed jobs, cancelling, running workflows and reviewing deployments are Pro (US$1.50 a month, with a 30-day trial).
GitHub and GitHub Actions are trademarks of GitHub, Inc.; IntelliJ IDEA is a trademark of JetBrains s.r.o. Node.js is a trademark of the OpenJS Foundation. This page is not affiliated with, sponsored or endorsed by GitHub, Inc., the OpenJS Foundation or JetBrains.
More: "Unable to resolve action" · ubuntu-latest moving to Ubuntu 26.04 · The retired macos-14 label · "Resource not accessible by integration" · GitHub Actions plugins for IntelliJ IDEA compared · 日本語