Skip to content

Commit 89cd54f

Browse files
authored
Merge pull request #2619 from appwrite/blog/nodejs-v25-whats-new
Add blog post on what's new in Node.js v25.2
2 parents 5900023 + 5520964 commit 89cd54f

File tree

2 files changed

+320
-0
lines changed

2 files changed

+320
-0
lines changed
Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
---
2+
layout: post
3+
title: "What's new in Node.js v25.2: Web Storage, V8 14.1, permissions and more"
4+
description: Node.js v25.2.1 brings V8 14.1, experimental Web Storage, network permissions with --allow-net, and performance optimizations. Learn about the key features and what they mean for your applications.
5+
date: 2025-11-25
6+
cover: /images/blog/nodejs-v25-whats-new/cover.png
7+
timeToRead: 9
8+
author: ebenezer-don
9+
category: news
10+
featured: false
11+
---
12+
13+
Node.js v25.2.1, the current release as of November 17, 2025, represents the latest evolution in the v25 series. This release brings performance improvements, security features, and web standards alignment, though it also demonstrates how the Node.js team handles breaking changes.
14+
15+
If you've been following the Node.js ecosystem, you know that odd-numbered releases like v25 aren't designated for long-term support (LTS). But that doesn't make them any less important. These releases serve as a testing ground for features that will eventually stabilize in future LTS versions.
16+
17+
In this article, we'll break down what's new in the Node.js v25 series, explore the major features introduced, discuss the localStorage controversy that led to v25.2.1, and examine what these changes mean for your applications.
18+
19+
# V8 14.1 engine upgrade {% #v8-14-1-engine-upgrade %}
20+
21+
Node.js v25 ships with **V8 14.1**, Google's JavaScript and WebAssembly engine that powers Chrome. This upgrade brings several performance improvements that directly impact how your code runs.
22+
23+
## Major JSON.stringify improvements
24+
25+
One of the most significant improvements in V8 14.1 is the optimization of `JSON.stringify`. If you've ever worked with large objects or arrays that need to be serialized to JSON, you'll appreciate this.
26+
27+
According to V8's benchmarks, `JSON.stringify` is now **more than 2x faster** on the JetStream2 benchmark. This matters when you're building APIs that return JSON responses, handling data transformations in serverless functions, or working with any system that relies heavily on JSON serialization.
28+
29+
```javascript
30+
const largeObject = {
31+
users: Array.from({ length: 10000 }, (_, i) => ({
32+
id: i,
33+
name: `User ${i}`,
34+
email: `user${i}@example.com`,
35+
metadata: { createdAt: new Date(), status: 'active' }
36+
}))
37+
};
38+
39+
// This operation is now significantly faster in Node.js v25
40+
const jsonString = JSON.stringify(largeObject);
41+
```
42+
43+
## WebAssembly and JIT pipeline optimizations
44+
45+
V8 14.1 also brings ongoing improvements to WebAssembly support and the Just-In-Time (JIT) compilation pipeline. These changes might not be immediately visible in your day-to-day code, but they contribute to better overall runtime performance.
46+
47+
# Native Web Storage API support {% #native-web-storage-api-support %}
48+
49+
One of the challenges when building full-stack JavaScript applications has been the gap between browser and server-side APIs. Node.js v25 narrows this gap by enabling **Web Storage API** by default.
50+
51+
This means you can now use `localStorage` and `sessionStorage` directly in Node.js, just like you would in the browser.
52+
53+
```javascript
54+
// Store data in localStorage
55+
localStorage.setItem('user', JSON.stringify({ name: 'Jane Doe' }));
56+
57+
// Retrieve data
58+
const user = JSON.parse(localStorage.getItem('user'));
59+
console.log(user.name); // Output: Jane Doe
60+
61+
// Clear storage
62+
localStorage.removeItem('user');
63+
```
64+
65+
## Why this matters
66+
67+
For developers working with frameworks like Next.js, Remix, or Astro, this standardization makes it easier to share code between client and server. You can write utilities that work in both environments without needing to check which context you're in or use different APIs.
68+
69+
## The localStorage controversy
70+
71+
Here's where things get interesting. The Web Storage API in Node.js is still marked as **experimental**, and v25.2.0 introduced a change that caused significant problems in the ecosystem.
72+
73+
In v25.2.0, Node.js started throwing errors when accessing `localStorage` without a configured storage path. The intent was to align with web specifications, but this broke popular tools like Jest, Vite, and other frameworks that relied on the previous behavior.
74+
75+
Developers upgrading to v25.2.0 encountered errors like:
76+
77+
```
78+
SecurityError: Cannot initialize local storage without a `--localstorage-file` path
79+
```
80+
81+
This broke test suites and build processes across the ecosystem. The Node.js team received enough feedback that they decided this change was too breaking for a semver-minor release.
82+
83+
**Node.js v25.2.1** (released November 17, 2025) reverted this behavior. The throwing behavior has been postponed to Node.js v26.0.0, giving developers more time to adapt to the change.
84+
85+
This episode highlights an important aspect of non-LTS releases: they're testing grounds for features, and sometimes those features need to be adjusted based on real-world feedback. If you're using Web Storage in Node.js v25, it works, but be prepared for stricter behavior in future versions.
86+
87+
# Network permissions with --allow-net {% #network-permissions-with-allow-net %}
88+
89+
Node.js has traditionally been permissive when it comes to what your code can access. If you run a script, it can read files, make network requests, and interact with the system without restrictions. This flexibility is convenient, but it also poses security risks, especially when running untrusted code.
90+
91+
Node.js v25 expands the **permission model** with a new `--allow-net` flag, giving you finer control over network access.
92+
93+
## How it works
94+
95+
The `--allow-net` flag allows you to explicitly grant network permissions to your application. This is similar to Deno's security model, which requires explicit permissions for different operations.
96+
97+
```bash
98+
# Allow network access to specific hosts (requires --permission flag)
99+
node --permission --allow-net=api.example.com,cdn.example.com server.js
100+
101+
# Allow all network access (requires --permission flag)
102+
node --permission --allow-net server.js
103+
```
104+
105+
This approach encourages **secure-by-default** applications. By requiring explicit permission for network operations, you reduce the risk of unintended behavior or vulnerabilities in dependencies that might make unauthorized network requests.
106+
107+
For production systems, multi-tenant environments, or any scenario where you need to limit what your code can do, this is a valuable addition.
108+
109+
# Built-in Uint8Array base64/hex conversion {% #built-in-uint8array-base64-hex-conversion %}
110+
111+
Working with binary data has always been a bit cumbersome in JavaScript. Converting between `Uint8Array` and formats like base64 or hex usually required either using the `Buffer` API or pulling in a third-party library.
112+
113+
Node.js v25 changes this by adding **built-in methods** to convert `Uint8Array` directly to base64 or hex strings.
114+
115+
```javascript
116+
// Create a Uint8Array
117+
const data = new Uint8Array([72, 101, 108, 108, 111]);
118+
119+
// Convert to base64
120+
const base64 = data.toBase64();
121+
console.log(base64); // Output: SGVsbG8=
122+
123+
// Convert to hex
124+
const hex = data.toHex();
125+
console.log(hex); // Output: 48656c6c6f
126+
```
127+
128+
## Practical use cases
129+
130+
This is useful when working with:
131+
132+
- **File uploads:** Encoding binary data for transmission
133+
- **Cryptographic operations:** Converting hash outputs to readable formats
134+
- **API integrations:** Many APIs expect base64-encoded binary data
135+
- **WebSocket communication:** Encoding binary frames
136+
137+
By making these conversions native, Node.js removes the dependency on external libraries and improves performance since these operations are now handled at the engine level.
138+
139+
# WebAssembly JSPI support {% #webassembly-jspi-support %}
140+
141+
WebAssembly continues to evolve, and Node.js v25 enables **JavaScript Promise Integration (JSPI)** for WebAssembly modules.
142+
143+
JSPI allows synchronous WebAssembly code to interact with asynchronous JavaScript APIs. This is important because WebAssembly is inherently synchronous, but JavaScript's ecosystem is heavily async-based.
144+
145+
## Why this is useful
146+
147+
Before JSPI, if you wanted to call an async JavaScript function from WebAssembly, you had to use complex workarounds involving callbacks or state machines. JSPI simplifies this by letting WebAssembly suspend and resume execution while waiting for async operations.
148+
149+
This is valuable for:
150+
151+
- **High-performance computing:** Running CPU-intensive operations (like scientific simulations or video encoding) in WebAssembly while interacting with async I/O
152+
- **Game engines:** Integrating WebAssembly-based game logic with async network calls for multiplayer features or asset loading
153+
- **Image and video processing:** Using WebAssembly for fast image manipulation (filters, compression, format conversion) while reading/writing files asynchronously
154+
- **Data processing:** Combining WebAssembly's speed for parsing large datasets with JavaScript's async file system or database operations
155+
156+
# Portable compile cache {% #portable-compile-cache %}
157+
158+
Node.js compiles JavaScript code to bytecode before executing it. This compilation step takes time, especially for large applications. To speed up subsequent runs, Node.js caches the compiled bytecode.
159+
160+
Node.js v25 introduces **portable compile cache**, which allows caches to be reused even when you move your project directory. Previously, compile caches used absolute file paths, meaning if you moved your project or deployed it to a different environment, the cache couldn't be reused.
161+
162+
You can enable portable caching in two ways:
163+
164+
```bash
165+
# Enable portable compile cache via environment variable
166+
NODE_COMPILE_CACHE_PORTABLE=1 node app.js
167+
```
168+
169+
Or programmatically:
170+
171+
```javascript
172+
// Enable portable compile cache via API
173+
module.enableCompileCache({
174+
directory: '/path/to/cache/dir',
175+
portable: true
176+
});
177+
```
178+
179+
## Impact on serverless and containers
180+
181+
This feature is especially useful for:
182+
183+
- **Serverless functions:** Reuse caches across different function invocations
184+
- **Docker containers:** Share caches between container builds
185+
- **CI/CD pipelines:** Speed up test runs by reusing compilation artifacts
186+
187+
# Type stripping marked as stable {% #type-stripping-marked-as-stable %}
188+
189+
Node.js v25.2 marks **type stripping** as stable. This feature allows you to run TypeScript-like syntax directly in Node.js without needing a separate build step.
190+
191+
Type stripping removes type annotations from your code at runtime, but it doesn't perform type checking. You still need the TypeScript compiler (`tsc`) for that.
192+
193+
```typescript
194+
// This works natively in Node.js v25.2
195+
function greet(name: string): void {
196+
console.log(`Hello, ${name}!`);
197+
}
198+
199+
greet('World');
200+
```
201+
202+
## When to use it
203+
204+
Type stripping is ideal for:
205+
206+
- **Rapid prototyping:** Write TypeScript without setting up a build pipeline
207+
- **Small scripts:** Run one-off TypeScript files without compilation
208+
- **Learning TypeScript:** Experiment with TypeScript syntax without tooling overhead
209+
210+
For production applications, you'll likely still want a proper TypeScript setup with full type checking, but type stripping removes friction for simpler use cases.
211+
212+
# Performance improvements {% #performance-improvements %}
213+
214+
Beyond the headline features, Node.js v25.2 includes several performance optimizations:
215+
216+
## Buffer concatenation speedup
217+
218+
The implementation of buffer concatenation has been improved using `TypedArray#set`, which reduces the time needed to combine multiple buffers. This is useful when working with streams or assembling data from multiple sources.
219+
220+
## Console logging optimization
221+
222+
Single-string logging in the `console` module has been optimized. If you're doing a lot of logging (especially in development), you'll notice faster output.
223+
224+
## Crypto argument validation
225+
226+
The crypto module now performs argument validation more efficiently in fast paths, reducing overhead for common cryptographic operations.
227+
228+
# What's specific to v25.2.1 {% #whats-specific-to-v25-2-1 %}
229+
230+
While most of the features we've discussed came with v25.0.0 or v25.2.0, v25.2.1 includes a few specific changes worth noting.
231+
232+
## Crypto fix: RSA-PSS saltLength default
233+
234+
v25.2.1 fixed an issue where the documented RSA-PSS `saltLength` default wasn't being used correctly. If you're working with RSA-PSS signatures in the crypto module, this ensures the implementation matches the documented behavior.
235+
236+
```javascript
237+
const crypto = require('crypto');
238+
239+
// The default saltLength now matches documentation
240+
const sign = crypto.createSign('RSA-SHA256');
241+
// ...
242+
```
243+
244+
## V8 engine backport
245+
246+
The release includes a critical V8 engine patch that was backported to improve stability and performance. While the specific details are technical, these backports typically address edge cases or bugs discovered in production environments.
247+
248+
## Documentation clarity on Web Storage
249+
250+
Beyond reverting the throwing behavior, v25.2.1 also clarified the experimental status of Web Storage across documentation, source code, and library code. This makes it clearer to developers that while the feature is available, it's still evolving and may change in future releases.
251+
252+
# Deprecated API removals {% #deprecated-api-removals %}
253+
254+
Node.js v25 continues the tradition of cleaning up deprecated APIs. Several long-deprecated features have been removed:
255+
256+
## SlowBuffer removal
257+
258+
The `SlowBuffer` object has been completely removed due to security vulnerabilities. If you were still using it, you should migrate to `Buffer.allocUnsafeSlow()`.
259+
260+
```javascript
261+
// Old (removed in v25)
262+
const buf = new SlowBuffer(10);
263+
264+
// New
265+
const buf = Buffer.allocUnsafeSlow(10);
266+
```
267+
268+
## Deprecated crypto options
269+
270+
Certain crypto options, like default lengths for `shake128` and `shake256`, are now deprecated at runtime and will be removed in future versions.
271+
272+
## Filesystem constants
273+
274+
Filesystem permission constants (`fs.F_OK`, `fs.R_OK`, `fs.W_OK`, `fs.X_OK`) have been removed. These were already marked as deprecated, and you should use the corresponding constants from the `fs.constants` object instead.
275+
276+
```javascript
277+
// Old (removed in v25)
278+
fs.access(path, fs.R_OK, callback);
279+
280+
// New
281+
fs.access(path, fs.constants.R_OK, callback);
282+
```
283+
284+
# When should you use Node.js v25? {% #when-should-you-use-nodejs-v25 %}
285+
286+
Node.js v25 is a **Current** release, not an LTS release. This means it's designed for developers who want to experiment with the latest features and provide feedback, but it's not recommended for production applications that require long-term stability.
287+
288+
## Use Node.js v25 if:
289+
290+
- You're building side projects or prototypes
291+
- You want to test new features before they land in LTS
292+
- You're contributing to the Node.js ecosystem and need to validate changes
293+
- You're working on applications that can tolerate breaking changes
294+
295+
## Stick with LTS if:
296+
297+
- You're running production applications
298+
- You need long-term support and security updates
299+
- Your team relies on ecosystem stability
300+
- You're working in enterprise environments with strict upgrade policies
301+
302+
The next LTS release is expected in October 2026 with Node.js v26, which will incorporate many of the features tested in v25.
303+
304+
305+
# Conclusion
306+
307+
Node.js v25.2.1 represents a meaningful step forward for the runtime, though it also demonstrates the value of iterative development. The combination of performance improvements, security features, and web standards alignment shows that Node.js continues to evolve in response to developer needs.
308+
309+
While v25 isn't an LTS release, it gives us a preview of what's coming and an opportunity to provide feedback before these features stabilize. Whether you're working with high-performance JSON operations, building cross-platform applications that benefit from Web Storage, or experimenting with WebAssembly, there's something here worth exploring.
310+
311+
If you're interested in learning more about modern JavaScript runtimes, you might enjoy reading about [Deno vs Bun](https://appwrite.io/blog/post/deno-vs-bun-javascript-runtime) or exploring [how Deno 2.0 works with Appwrite Functions](https://appwrite.io/blog/post/deno-2-appwrite-functions).
312+
313+
You can reach out to us on [Discord](https://appwrite.io/discord) if you have any questions or feedback.
314+
315+
# More resources
316+
317+
- [Node.js v25.2.1 release notes](https://nodejs.org/en/blog/release/v25.2.1)
318+
- [Node.js v25.2.0 release notes](https://nodejs.org/en/blog/release/v25.2.0)
319+
- [Why you need to try the new Bun function runtime](/blog/post/why-you-need-to-try-the-new-bun-runtime)
320+
- [Announcing Deno support on Appwrite Cloud](/blog/post/deno-runtime-announcment)
693 KB
Loading

0 commit comments

Comments
 (0)