- Compatibility flags·续1
- Enhanced error serialization
- Use an isolated PID namespace for containers
- Spec-compliant TextEncoderStream/TextDecoderStream backpressure
- Spec-compliant WritableStream writer behavior
- Enable global Performance classes
- Enable node:child_process module
- Enable node:perf_hooks module
- Enable node:readline module
- Enable node:repl module
- Enable node:tty module
- Enable node:v8 module
- Enable node:worker_threads module
- WebSocket standard binary type
- Expose error codes in Queue operations
- WebSocket auto-reply to close
- Dedicated CJK TextDecoder implementation
- Defer unhandled rejection processing to after microtask checkpoint
Compatibility flags·续1
import { WorkflowEntrypoint, NonRetryableError } from "cloudflare:workers";
export class MyWorkflow extends WorkflowEntrypoint {
async run(event, step) {
await step.do("my-step", async () => {
throw new NonRetryableError("custom error message");
// Without this flag: error.message === "The execution of the Workflow instance was terminated, as a step threw an NonRetryableError and it was not handled"
// With this flag: error.message === "custom error message"
});
}
}
With the workflows_preserve_non_retryable_error_message flag enabled, the original error message and name are preserved, making it easier to debug and handle specific error cases in your Workflow code.
Enhanced error serialization
| Default as of | 2026-04-21 |
|---|---|
| Flag to enable | enhanced_error_serialization |
| Flag to disable | legacy_error_serialization |
When enhanced_error_serialization is enabled, errors serialized using structuredClone() or V8 serialization support more error types and include own properties on the error object.
Note that when enabled, deserialization of errors will not preserve the original stack trace by default.
Previously, only basic Error types were serialized, and own properties added to error objects were lost during serialization.
Use an isolated PID namespace for containers
| Default as of | 2026-04-01 |
|---|---|
| Flag to enable | containers_pid_namespace |
| Flag to disable | no_containers_pid_namespace |
When containers_pid_namespace is set, containers will use an isolated PID namespace. The ENTRYPOINT of your container will have PID 1.
When unset, the container shares the PID namespace with the virtual machine (VM) containing the container. The ENTRYPOINT of your container will not have PID 1 and other processes running on the VM (that are not part of your container) will be visible.
Spec-compliant TextEncoderStream/TextDecoderStream backpressure
| Default as of | 2026-03-24 |
|---|---|
| Flag to enable | encoder_stream_spec_compliant_backpressure |
| Flag to disable | no_encoder_stream_spec_compliant_backpressure |
When encoder_stream_spec_compliant_backpressure is enabled, TextEncoderStream and TextDecoderStream use a readable-side high water mark of 0, as specified by the WHATWG Encoding Standard ↗︎.
With a high water mark of 0, the readable side starts with backpressure applied, so writes correctly block until a reader pulls. Previously, the high water mark defaulted to 1, which caused pull() to fire at startup, clearing backpressure before any write occurred.
Spec-compliant WritableStream writer behavior
| Default as of | 2026-03-24 |
|---|---|
| Flag to enable | writable_stream_spec_compliant_writer |
| Flag to disable | no_writable_stream_spec_compliant_writer |
When writable_stream_spec_compliant_writer is enabled, several WritableStream spec compliance issues around writer lock and release behavior are fixed to match the WHATWG Streams Standard ↗︎.
Enable global Performance classes
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | enable_global_performance_classes |
| Flag to disable | disable_global_performance_classes |
When enable_global_performance_classes is enabled, the following classes are available on the global scope: PerformanceEntry, PerformanceMark, PerformanceMeasure, PerformanceResourceTiming, PerformanceObserver, and PerformanceObserverEntryList.
These classes are also implicitly enabled by the enable_nodejs_perf_hooks_module flag.
This flag is automatically enabled for Workers using a compatibility date of 2026-03-17 or later when nodejs_compat is enabled.
Enable node:child_process module
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | enable_nodejs_child_process_module |
| Flag to disable | disable_nodejs_child_process_module |
The enable_nodejs_child_process_module flag enables the node:child_process module stub in Workers.
This flag is automatically enabled for Workers using a compatibility date of 2026-03-17 or later when nodejs_compat is enabled.
See the Node.js documentation ↗︎ for more details about the node:child_process API.
Enable node:perf_hooks module
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | enable_nodejs_perf_hooks_module |
| Flag to disable | disable_nodejs_perf_hooks_module |
The enable_nodejs_perf_hooks_module flag enables the node:perf_hooks module in Workers. This flag also implicitly enables global Performance classes (PerformanceEntry, PerformanceMark, PerformanceMeasure, PerformanceResourceTiming, PerformanceObserver, and PerformanceObserverEntryList).
This flag is automatically enabled for Workers using a compatibility date of 2026-03-17 or later when nodejs_compat is enabled.
See the Node.js documentation ↗︎ for more details about the node:perf_hooks API.
Enable node:readline module
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | enable_nodejs_readline_module |
| Flag to disable | disable_nodejs_readline_module |
The enable_nodejs_readline_module flag enables the node:readline module stub in Workers.
This flag is automatically enabled for Workers using a compatibility date of 2026-03-17 or later when nodejs_compat is enabled.
See the Node.js documentation ↗︎ for more details about the node:readline API.
Enable node:repl module
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | enable_nodejs_repl_module |
| Flag to disable | disable_nodejs_repl_module |
The enable_nodejs_repl_module flag enables the node:repl module stub in Workers.
This flag is automatically enabled for Workers using a compatibility date of 2026-03-17 or later when nodejs_compat is enabled.
See the Node.js documentation ↗︎ for more details about the node:repl API.
Enable node:tty module
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | enable_nodejs_tty_module |
| Flag to disable | disable_nodejs_tty_module |
The enable_nodejs_tty_module flag enables the node:tty module stub in Workers.
This flag is automatically enabled for Workers using a compatibility date of 2026-03-17 or later when nodejs_compat is enabled.
See the Node.js documentation ↗︎ for more details about the node:tty API.
Enable node:v8 module
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | enable_nodejs_v8_module |
| Flag to disable | disable_nodejs_v8_module |
The enable_nodejs_v8_module flag enables the node:v8 module stub in Workers.
This flag is automatically enabled for Workers using a compatibility date of 2026-03-17 or later when nodejs_compat is enabled.
See the Node.js documentation ↗︎ for more details about the node:v8 API.
Enable node:worker_threads module
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | enable_nodejs_worker_threads_module |
| Flag to disable | disable_nodejs_worker_threads_module |
The enable_nodejs_worker_threads_module flag enables the node:worker_threads module stub in Workers.
This flag is automatically enabled for Workers using a compatibility date of 2026-03-17 or later when nodejs_compat is enabled.
See the Node.js documentation ↗︎ for more details about the node:worker_threads API.
WebSocket standard binary type
| Default as of | 2026-03-17 |
|---|---|
| Flag to enable | websocket_standard_binary_type |
| Flag to disable | no_websocket_standard_binary_type |
This flag controls the default value of the binaryType property on WebSocket, which in turn controls how binary frames are delivered to the message event. With the flag active, binaryType defaults to "blob" and binary frames arrive as Blob ↗︎ objects, matching the WebSocket specification ↗︎ and standard browser behavior. Without the flag, binaryType defaults to "arraybuffer" and binary frames arrive as ArrayBuffer ↗︎, matching the runtime's historical behavior.
The binaryType property itself is available on every WebSocket regardless of the flag. Assigning a value overrides the default for that specific WebSocket:
const resp = await fetch("https://example.com", {
headers: { Upgrade: "websocket" },
});
const ws = resp.webSocket;
// Opt back into ArrayBuffer delivery before calling accept().
ws.binaryType = "arraybuffer";
ws.accept();
ws.addEventListener("message", (event) => {
// event.data is an ArrayBuffer for binary frames.
});
If you are not ready to migrate and want to keep ArrayBuffer as the default for every WebSocket in your Worker, add the no_websocket_standard_binary_type flag to your Wrangler configuration file.
This flag has no effect on the Durable Object hibernatable WebSocket webSocketMessage handler, which always receives binary data as ArrayBuffer.
Expose error codes in Queue operations
| Default as of | 2026-03-12 |
|---|---|
| Flag to enable | queue_expose_error_codes |
| Flag to disable | no_queue_expose_error_codes |
When queue_expose_error_codes is enabled, Queue operations will include detailed error information, including error codes and causes, making it easier to handle and diagnose queue-related errors programmatically.
WebSocket auto-reply to close
| Default as of | 2026-04-07 |
|---|---|
| Flag to enable | web_socket_auto_reply_to_close |
| Flag to disable | web_socket_manual_reply_to_close |
When a server sends a WebSocket Close frame, the Workers runtime now automatically sends a reciprocal Close frame and transitions readyState to CLOSED before firing the close event. This matches the WebSocket spec ↗︎ and browser behavior.
Previously, receiving a server-initiated Close frame left the WebSocket in CLOSING and required the application to call close() itself. With this flag active, you no longer need to call close() in your close event handler. The runtime handles the close handshake automatically.
const [client, server] = Object.values(new WebSocketPair());
server.accept();
server.addEventListener("close", (event) => {
// readyState is already CLOSED — no need to call server.close().
console.log(server.readyState); // WebSocket.CLOSED
console.log(event.code); // 1000
console.log(event.wasClean); // true
}, { once: true });
If you do still call close() inside the handler, the call is silently ignored. This means existing code that manually replies to Close frames will not break when you update your compatibility date.
The automatic close behavior can interfere with WebSocket proxying. When a Worker proxies between a client and a backend, the old behavior allowed the Worker to observe a backend Close frame without the runtime tearing down the connection, giving the Worker time to coordinate a clean close on the client side. To support this pattern, the accept() method now accepts an option allowHalfOpen. Call ws.accept({ allowHalfOpen: true }) to restore the old half-open behavior regardless of the compatibility flag.
const [client, server] = Object.values(new WebSocketPair());
// Opt into half-open mode for proxying
server.accept({ allowHalfOpen: true });
server.addEventListener("close", (event) => {
// With allowHalfOpen true, readyState is still CLOSING here,
// giving you time to coordinate the close on the other side.
console.log(server.readyState); // WebSocket.CLOSING
// Manually close when ready.
server.close(1000, "done");
}, { once: true });
Note that there is no corresponding option to the WebSocket constructor. WebSockets constructed with new WebSocket will always auto-reply to closes after this flag takes effect. WebSockets constructed this way are automatically "accepted", so there is no opportunity to pass the option to accept(). If you are creating a WebSocket with new WebSocket, but you need half-open behavior, you will need to switch to using fetch() instead.
// This does not allow half-open:
let ws = new WebSocket("wss://example.com");
// But you can do this instead:
let resp = await fetch("https://example.com", {
headers: { "Upgrade": "websocket" }
});
if (!resp.webSocket) {
throw new Error("WebSocket handshake not accepted");
}
let ws = resp.webSocket;
ws.accept({ allowHalfOpen: true });
For more information, refer to the WebSocket API documentation.
Dedicated CJK TextDecoder implementation
| Default as of | 2026-03-03 |
|---|---|
| Flag to enable | text_decoder_cjk_decoder |
| Flag to disable | disable_text_decoder_cjk_decoder |
When text_decoder_cjk_decoder is enabled, a dedicated CJK TextDecoder implementation is used for CJK encoding overrides and Big5 lead-byte handling, instead of the legacy ICU-only code path. This improves spec compliance for CJK text decoding.
Defer unhandled rejection processing to after microtask checkpoint
| Default as of | 2026-03-03 |
|---|---|
| Flag to enable | unhandled_rejection_after_microtask_checkpoint |
| Flag to disable | no_unhandled_rejection_after_microtask_checkpoint |
When unhandled_rejection_after_microtask_checkpoint is enabled, unhandledrejection event processing is deferred until the microtask checkpoint completes. This avoids misfires on multi-tick promise chains where a rejection handler is added in a later microtask.
Previously, unhandled rejection processing could fire prematurely before all microtasks in the current checkpoint had been processed, leading to false unhandledrejection events for promises that were actually handled.
