Node.js 24.0.0 was released on 6 May 2025. The release post calls it the Current line for the next six months and says it will enter long-term support (LTS) in October. Your Vue components run in the browser, but Vite, Vitest, your package manager and your CI all run on Node, and so does any server that renders your pages.
The short answer: Vite 6 and Vitest 3 accept Node 24, so develop and test on it now, and keep production builds on Node 22 until 24 becomes LTS. Run your build once on 24 first to catch deprecated APIs.
What shipped in Node 24.0.0
The release post lists these notable changes:
- V8 13.6, which brings
Float16Array, explicit resource management (theusingdeclaration),RegExp.escape, WebAssembly Memory64 andError.isError. - npm 11.
AsyncLocalStoragenow usesAsyncContextFrameby default, which the post describes as a more efficient implementation of asynchronous context tracking.URLPatternis a global, so you no longer import it.- The permission model flag is now
--permissioninstead of--experimental-permission, a change the post ties to its increasing stability. - The test runner waits for subtests automatically, so you no longer
awaiteacht.test()call. - Undici 7, the library behind the global
fetch. - On Windows, building Node itself now requires ClangCL; MSVC support was removed. This only affects people compiling Node from source.
For a Vue project, two of those touch daily work: npm 11 and URLPattern.
npm 11 is what npm install now runs. Its own engines field is ^20.17.0 || >=22.9.0. That does not affect anyone on Node 24, but if your team pins npm 11 for everyone, a colleague on Node 20.10 will be told to upgrade.
You can start using URLPattern straight away, in server code or in tests. It matches URLs the way a router matches paths:
const pattern = new URLPattern({ pathname: '/users/:id' })
const match = pattern.exec('https://example.com/users/42')
console.log(match?.pathname.groups.id) // "42"
exec() returns null for a URL that does not match, hence match?..
Check your scripts for deprecated and removed APIs
The release post also lists runtime deprecations and removals. A runtime deprecation still works but prints a DeprecationWarning when the code runs. A removal means the API is gone: calling a removed function throws a TypeError, and a removed property reads as undefined. The ones most likely to appear in a front-end project's scripts, build plugins or tests:
url.parse()is now a runtime deprecation. Use the WHATWGURLclass instead.SlowBufferis a runtime deprecation; useBuffer.allocUnsafeSlow(). Node 24.0.0 removed it too early and brokejsonwebtokenthrough its dependencies; 24.0.1 (8 May) puts it back, so skip 24.0.0.tls.createSecurePairis removed.dirent.pathis removed; readdirent.parentPathinstead.- The
fs.F_OK,fs.R_OK,fs.W_OKandfs.X_OKconstants are runtime deprecated in favour offs.constants.
You are most likely to meet url.parse(), because it sits in a decade of copy-pasted scripts. The replacement needs a base URL when the input is a bare path:
import { parse } from 'node:url'
const { pathname } = parse(link)
const { pathname } = new URL(link, 'https://example.com')
Without the second argument, new URL('/guide/') throws TypeError: Invalid URL. Any base works when you only read pathname.
To find the callers, run NODE_OPTIONS=--trace-deprecation npm run build on Node 24. Each warning names the API, and the stack trace under it shows which file called it. If the caller is your own script, each fix above is one line. If it is a dependency, upgrade it or file an issue. One exception: url.parse() only warns when your own code calls it (DEP0169), so a dependency that still uses it stays silent.
require() can load ES modules without a flag
Node has two module systems: CommonJS (require() and module.exports) and ES modules (import and export). Loading an ES module with require() is not in the release post, because the work landed in earlier releases. The modules documentation records three steps:
- Added behind the
--experimental-require-moduleflag in 22.0 and 20.17. - No flag needed from 23.0, 22.12 and 20.19.
- No experimental warning from 23.5, 22.13 and 20.19.
Node 24 inherits all of that, so a plain require() of an ES module works with no flag and no warning. The docs still mark it as a release candidate, the last stage before stable, and it has one limit: a module with top-level await cannot be required (require() throws ERR_REQUIRE_ASYNC_MODULE), so load that one with import().
This matters because more packages now ship as ES modules only (VueUse 13, released in March, is one), and a CommonJS config file or old build script can now load them with require() instead of a dynamic import(). If your project still has a postcss.config.js or a tailwind.config.js in CommonJS form, the pressure to convert it has dropped.
Vite 6 and Vitest 3 accept Node 24
Vite 6.3 is the current minor (6.3.0 on 16 April, 6.3.5 on 5 May). The Vite 6 guide says "Vite requires Node.js version 18+ or 20+", and the package's engines field is ^18.0.0 || ^20.0.0 || >=22.0.0. Node 24 satisfies >=22.0.0, so npm install does not complain. Vitest 3.1 declares the same range. A create-vue project needs no change.
Accepted is not the same as tested: Vite 6.3.5 and Vitest 3.1.3 run their own CI on Node 18, 20 and 22, not 24. Your build and tests are the real check, and the CI matrix below runs them.
Keep production on Node 22 until October
Until then, 24 takes most non-breaking changes that land on Node's main branch, with new features every few weeks. That is what you want on a laptop and not what you want on a server, where an Active LTS line takes only changes the Release team has judged stable. A hosting platform may not offer 24 at all yet. For a static Vue site, "production" is just the build step, so keeping it on 22 costs nothing.
Node 18 reached end of life on 30 April 2025 and gets no more fixes. If a machine or a CI image still runs 18, this is the week to move it to 22.
Pin the version with .nvmrc and engines
Pin the version so nobody has to remember it. A .nvmrc file tells nvm and fnm which version to use, and engine-strict makes npm refuse to install when the running Node is outside the engines range in package.json:
echo "22" > .nvmrc
echo "engine-strict=true" >> .npmrc
{
"engines": {
"node": ">=22.12.0"
}
}
The floor is 22.12 rather than 22.0 because that is the first 22 release where require() of ES modules works without a flag, so every machine that passes the check behaves the same way around ESM-only packages. The range is open at the top, so Node 24 passes too.
Test on Node 22 and 24 in CI
Run the test suite and the build on both lines. When the 24 job goes red and the 22 job stays green, you learn about the problem before a user does.
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [22, 24]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: npm
- run: npm ci
- run: npx vitest --run
- run: npm run build
node-version: 24 matches any 24.x, so patch releases need no edit. Add check-latest: true under with: if every run must use the newest patch rather than one cached on the runner. In October, when 24 becomes LTS, swap the roles: 24 goes into .nvmrc and 22 stays in the matrix until you no longer deploy to it.