How to Upgrade to Node.js 26 Before It Goes LTS on October 28
Node.js 26 becomes the long-term support line next week, and Node 24 has just moved to maintenance. Here is what breaks, what is new, and a safe rollout order.
On this page 9 sections
Node.js 26 moves to long-term support on October 28, 2026, and Node.js 24 entered maintenance on October 20. To upgrade, test your services on Node 26 now, fix removed APIs such as the legacy stream modules, run your suite in CI on both versions, then roll out gradually. Treat the LTS date as your deadline to be ready.
Backtrace covers the tooling that decides how fast engineering teams ship, and runtime upgrades sit near the top of that list. This guide is for developers and platform engineers who run Node services in production. It covers the schedule, the breaking changes that matter, a six-step plan and how to test before you commit.
What Does the Node.js 26 LTS Schedule Mean for You?
It means Node 26 is the version to target for new production work from October 28, while Node 24 stops getting new features. The official Node.js release schedule lists Node 26 starting May 5, 2026, entering LTS on October 28, 2026 and ending on April 30, 2029. Node 24 enters maintenance on October 20, 2026.
The Node.js previous releases page also notes that production applications should only use Active LTS or Maintenance LTS releases. Until the 28th, Node 26 is labeled Current. Odd-numbered Node 25 has already reached end of life, so teams that jumped on it need to move anyway.
Maintenance status is not a crisis. Node 24 still receives critical fixes. But you gain more time and better support by planning the move now instead of during an incident.
What Changed in Node.js 26
The release notes for Node.js 26.0.0 list a few headline changes. The most visible is that the Temporal API is on by default. Temporal is a modern date and time API meant to replace the error-prone legacy Date object.
V8 moved to version 14.6, which matches Chromium 146. That adds Map upsert helpers such as getOrInsert and getOrInsertComputed, plus Iterator.concat for joining iterators. The built-in fetch client also moved to Undici 8.0.2.
None of these features forces a code change. They are optional upgrades you can adopt after the move. The breaking changes are the part that needs attention first.
Which Breaking Changes Are Most Likely to Hit You?
Removed APIs and build requirements are the likeliest causes of failures. The table below lists the changes from the release notes that most often affect application teams, with the usual fix for each.
| Change | Who it affects | Typical fix |
|---|---|---|
| http.Server writeHeader removed | Older HTTP code | Use writeHead instead |
| Legacy _stream_* modules removed | Old libraries that deep-import | Import from the stream module; update the dependency |
| --experimental-transform-types removed | TypeScript-in-Node users | Use a build step or another loader |
| module.register() deprecated at runtime | Custom loader setups | Plan a migration; expect warnings |
| NODE_MODULE_VERSION is 147 | Native addons | Rebuild every addon |
| Python 3.9 and GCC below 13.2 unsupported | Teams that build Node or addons from source | Update the build image |
Other behavior changes are smaller but worth a scan. Readable streams now read one buffer at a time, and localStorage returns undefined when no file is configured. The assert module also accepts printf-style messages.
Native addons deserve special attention. A new module version means any compiled dependency needs a rebuild or a new prebuilt binary. A single stale addon can stop a container from starting.
How to Upgrade to Node.js 26 in Six Steps
Follow this order to keep each step small and reversible:
- Inventory every place Node runs: services, CI images, build tools and developer machines.
- Pin the current version in an engines field and a version file so everyone tests the same runtime.
- Add Node 26 to your CI matrix next to your current version.
- Fix what fails, starting with removed APIs and rebuilt native addons.
- Deploy to a low-risk service first and watch error rates and memory for a week.
- Roll through the remaining services, then update base images and drop Node 24 from CI.
The matrix step does most of the work. If your pipeline already runs several versions, the cost is a single line. If it does not, our comparison of GitHub Actions and GitLab CI covers how each handles version matrices.
Pick the pilot service carefully. A good candidate has solid test coverage, modest traffic and an owner who will watch dashboards. An internal tool or a background worker is better than the checkout path. If the pilot week is quiet, you have real evidence for the bigger services.
Keep rollback easy. Build images for both versions and tag them clearly. A one-line revert beats a night of debugging.
How Do You Test an Upgrade Without Surprises?
Test beyond unit tests, because runtime upgrades break integration points. Run your full test suite on Node 26, then run a staging environment with real traffic replays. Watch for changed stream behavior, different error messages and slower cold starts.
A short test plan helps. Check these areas in order:
- Install: does a clean install work with your lockfile and package manager?
- Build: do bundlers, compilers and native addons build without warnings?
- Run: do services start, and do health checks pass?
- Load: do latency and memory match the old runtime under the same traffic?
Dependencies are the common failure source. Our package manager speed comparison is a useful companion, since reinstalling from scratch is part of any upgrade. Update dependencies that deep-import internal Node modules before you switch.
Supply chain hygiene fits this window too. Regenerating your lockfile is a good time to produce a fresh software bill of materials, as covered in our SBOM generation how-to.
Common Failures and What They Usually Mean
Most upgrade failures fall into a few patterns, and recognizing them saves hours. Use this list to match a symptom to its likely cause:
- A crash on startup that mentions a native module usually means an addon was built for an older module version.
- A "cannot find module" error for a stream path points to a library that deep-imports a removed underscore module.
- A TypeError on writeHeader means old HTTP code that needs writeHead.
- A build failure in a container often traces back to an old Python or compiler in the image.
- New deprecation warnings in logs usually come from loader hooks that call module.register().
The first two are the most common in practice. Both are dependency problems, not application bugs. The fix is usually to upgrade the package, not to patch your own code.
It helps to run Node with warnings turned into errors in a test job. That surfaces deprecations early, while you still have time to plan. Treat each warning as a ticket with an owner, not as noise to filter out of the logs.
Finally, check your tooling versions. Linters, bundlers and test runners sometimes pin an older Node range in their own configuration. Update those ranges when you update the runtime so developers get the same behavior locally and in CI.
Should You Adopt Temporal Right Away?
No, adopt it deliberately. Temporal is available without a flag in Node 26, but your dependencies, ORMs and date libraries may not understand Temporal objects yet. Using it at the edges of new code is safe. Replacing every Date in a large codebase in one pass is not.
A sensible approach is to start with new modules and keep existing Date handling. Write small adapters at the boundary, where data enters or leaves your code. Over time, the adapters shrink as libraries catch up.
Our read at Backtrace is that teams get the best return from Temporal in scheduling, billing and reporting code. Those areas suffer most from time zone and daylight-saving mistakes.
What If You Cannot Upgrade Yet?
Stay on Node 24 for now, but set a date. It remains supported in maintenance, and a short delay is reasonable if a critical dependency lags. Do not stay on an end-of-life version. Node 25 and Node 20 are both listed as end of life on the official releases page.
Also decide what you will do about libraries that never update. If a dependency is abandoned and breaks on Node 26, replace it rather than freezing your runtime for it. One stale package should not set the pace for the whole stack.
Document the blockers. A written list of the addon, library or build tool holding you back makes the decision visible. It also gives you something concrete to chase upstream.
Conclusion
Node.js 26 is ready to become the standard line on October 28. The main work is removing old API use, rebuilding native addons and proving the change in CI. The new features, including Temporal and the updated V8 and Undici, can wait until the migration is stable.
This week, add Node 26 to your CI matrix and read the failures. Fix the removed APIs first, then plan a staged rollout. Backtrace will keep tracking runtime releases as the LTS date arrives.