diff --git a/src/content/changelog/workers/2025-08-15-nodejs-fs.mdx b/src/content/changelog/workers/2025-08-15-nodejs-fs.mdx new file mode 100644 index 000000000000000..2d3e9f36e022fd5 --- /dev/null +++ b/src/content/changelog/workers/2025-08-15-nodejs-fs.mdx @@ -0,0 +1,60 @@ +--- +title: The Node.js and Web File System APIs in Workers +description: The node:fs and Web File System APIs are now available in Workers. +products: + - workers +date: 2025-08-15 +--- + +Implementations of the [`node:fs` module](https://nodejs.org/docs/latest/api/fs.html) and the [Web File System API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) are now available in Workers. + +## Using the `node:fs` module + +The `node:fs` module provides access to a virtual file system in Workers. You can use it to read and write files, create directories, and perform other file system operations. + +The virtual file system is ephemeral with each individual request havig its own isolated temporary file space. Files written to the file system will not persist across requests and will not be shared across requests or across different Workers. + +Workers running with the `nodejs_compat` compatibility flag will have access to the `node:fs` module by default when the compatibility date is set to `2025-09-01` or later. Support for the API can also be enabled using the `enable_nodejs_fs_module` compatibility flag together with the `nodejs_compat` flag. The `node:fs` module can be disabled using the `disable_nodejs_fs_module` compatibility flag. + +```js +import fs from "node:fs"; + +const config = JSON.parse(fs.readFileSync("/bundle/config.json", "utf-8")); + +export default { + async fetch(request) { + return new Response(`Config value: ${config.value}`); + }, +}; +``` + +There are a number of initial limitations to the `node:fs` implementation: + +- The glob APIs (e.g. `fs.globSync(...)`) are not implemented. +- The file watching APIs (e.g. `fs.watch(...)`) are not implemented. +- The file timestamps (modified time, access time, etc) are only partially supported. For now, these will always return the Unix epoch. + +Refer to the [Node.js documentation](https://nodejs.org/docs/latest/api/fs.html) for more information on the `node:fs` module and its APIs. + +## The Web File System API + +The Web File System API provides access to the same virtual file system as the `node:fs` module, but with a different API surface. The Web File System API is only available in Workers running with the `enable_web_file_system` compatibility flag. The `nodejs_compat` compatibility flag is not required to use the Web File System API. + +```js +const root = navigator.storage.getDirectory(); + +export default { + async fetch(request) { + const tmp = await root.getDirectoryHandle("/tmp"); + const file = await tmp.getFileHandle("data.txt", { create: true }); + const writable = await file.createWritable(); + const writer = writable.getWriter(); + await writer.write("Hello, World!"); + await writer.close(); + + return new Response("File written successfully!"); + }, +}; +``` + +As there are still some parts of the Web File System API tht are not fully standardized, there may be some differences between the Workers implementation and the implementations in browsers. diff --git a/src/content/docs/workers/runtime-apis/nodejs/fs.mdx b/src/content/docs/workers/runtime-apis/nodejs/fs.mdx new file mode 100644 index 000000000000000..7370ca8e36e279a --- /dev/null +++ b/src/content/docs/workers/runtime-apis/nodejs/fs.mdx @@ -0,0 +1,138 @@ +--- +pcx_content_type: configuration +title: fs +--- + +import { Render } from "~/components"; + + + +You can use [`node:fs`](https://nodejs.org/api/fs.html) to access a virtual file +system in Workers. + +The `node:fs` module is available in Workers runtimes that support Node.js +compatibility using the `nodejs_compat` compatibility flag. Any Worker +running with `nodejs_compat` enabled and with a compatibility date of +`2025-09-01` or later will have access to `node:fs` by default. It is +also possible to enable `node:fs` on Workers with an earlier compatibility +date using a combination of the `nodejs_compat` and `enable_nodejs_fs_module` +flags. To disable `node:fs` you can set the `disable_nodejs_fs_module` flag. + +```js +import { readFileSync, writeFileSync } from "node:fs"; + +const config = readFileSync("/bundle/config.txt", "utf8"); + +writeFileSync("/tmp/abc.txt", "Hello, world!"); +``` + +The Workers Virtual File System (VFS) is a memory-based file system that allows +you to read modules included in your Worker bundle as read-only files, access a +directory for writing temporary files, or access common +[character devices](https://linux-kernel-labs.github.io/refs/heads/master/labs/device_drivers.html) like +`/dev/null`, `/dev/random`, `/dev/full`, and `/dev/zero`. + +The directory structure initially looks like: + +``` + +/bundle +└── (one file for each module in your Worker bundle) +/tmp +└── (empty, but you can write files, create directories, symlinks, etc) +/dev +├── null +├── random +├── full +└── zero + +``` + +The `/bundle` directory contains the files for all modules included in your +Worker bundle, which you can read using APIs like `readFileSync` or +`read(...)`, etc. These are always read-only. Reading from the bundle +can be useful when you need to read a config file or a template. + +```js +import { readFileSync } from "node:fs"; + +// The config.txt file would be included in your Worker bundle. +// Refer to the Wrangler documentation for details on how to +// include additional files. +const config = readFileSync("/bundle/config.txt", "utf8"); + +export default { + async fetch(request) { + return new Response(`Config contents: ${config}`); + }, +}; +``` + +The `/tmp` directory is writable, and you can use it to create temporary files +or directories. You can also create symlinks in this directory. However, the +contents of `/tmp` are not persistent and are unique to each request. This means +that files created in `/tmp` within the context of one request will not be +available in other concurrent or subsequent requests. + +```js +import { writeFileSync, readFileSync } from "node:fs"; + +export default { + fetch(request) { + // The file `/tmp/hello.txt` will only exist for the duration + // of this request. + writeFileSync("/tmp/hello.txt", "Hello, world!"); + const contents = readFileSync("/tmp/hello.txt", "utf8"); + return new Response(`File contents: ${contents}`); + }, +}; +``` + +The `/dev` directory contains common character devices: + +- `/dev/null`: A null device that discards all data written to it and returns + EOF on read. +- `/dev/random`: A device that provides random bytes on reads and discards all + data written to it. Reading from `/dev/random` is only permitted when within + the context of a request. +- `/dev/full`: A device that always returns EOF on reads and discards all data + written to it. +- `/dev/zero`: A device that provides an infinite stream of zero bytes on reads + and discards all data written to it. + +All operations on the VFS are synchronous. You can use the synchronous, +asynchronous callback, or promise-based APIs provided by the `node:fs` module +but all operations will be performed synchronously. + +Timestamps for files in the VFS are currently always set to the Unix epoch +(`1970-01-01T00:00:00Z`). This means that operations that rely on timestamps, +like `fs.stat`, will always return the same timestamp for all files in the VFS. +This is a temporary limitation that will be addressed in a future release. + +Since all temporary files are held in memory, the total size of all temporary +files and directories created count towards your Worker’s memory limit. If you +exceed this limit, the Worker instance will be terminated and restarted. + +The file system implementation has the following limits: + +- The maximum total length of a file path is 4096 characters, including path + separators. Because paths are handled as file URLs internally, the limit + accounts for percent-encoding of special characters, decoding characters + that do not need encoding before the limit is checked. For example, the + path `/tmp/abcde%66/ghi%zz' is 18 characters long because the `%66`does +not need to be percent-encoded and is therefore counted as one character, +while the`%zz` is an invalid percent-encoding that is counted as 3 characters. +- The maximum number of path segments is 48. For example, the path `/a/b/c` is + 3 segments. +- The maximum size of an individual file is 128 MB total. + +The following `node:fs` APIs are not supported in Workers, or are only partially +supported: + +- `fs.watch` and `fs.watchFile` operations for watching for file changes. +- The `fs.globSync()` and other glob APIs have not yet been implemented. +- The `force` option in the `fs.rm` API has not yet bee implemented. +- Timestamps for files are always set to the Unix epoch (`1970-01-01T00:00:00Z`). +- File permissions and ownership are not supported. + +The full `node:fs` API is documented in the [Node.js documentation for `node:fs`](https://nodejs.org/api/fs.html). diff --git a/src/content/docs/workers/runtime-apis/nodejs/index.mdx b/src/content/docs/workers/runtime-apis/nodejs/index.mdx index 1ac5bf00a242bf0..d51dd1206ee24db 100644 --- a/src/content/docs/workers/runtime-apis/nodejs/index.mdx +++ b/src/content/docs/workers/runtime-apis/nodejs/index.mdx @@ -33,40 +33,40 @@ The runtime APIs from Node.js listed below as "🟢 supported" are currently nat [Deprecated or experimental APIs from Node.js](https://nodejs.org/docs/latest/api/documentation.html#stability-index), and APIs that do not fit in a serverless context, are not included as part of the list below: -| API Name | Natively supported by the Workers Runtime | -|--------------------------------------------------------------------------------------|-------------------------------------------| -| [Assertion testing](/workers/runtime-apis/nodejs/assert/) | 🟢 supported | -| [Asynchronous context tracking](/workers/runtime-apis/nodejs/asynclocalstorage/) | 🟢 supported | -| [Buffer](/workers/runtime-apis/nodejs/buffer/) | 🟢 supported | -| Console | 🟢 supported | -| [Crypto](/workers/runtime-apis/nodejs/crypto/) | 🟢 supported | -| [Debugger](/workers/observability/dev-tools/) | 🟢 supported via [Chrome Dev Tools integration](/workers/observability/dev-tools/) | -| [Diagnostics Channel](/workers/runtime-apis/nodejs/diagnostics-channel/) | 🟢 supported | -| [DNS](/workers/runtime-apis/nodejs/dns/) | 🟢 supported | -| Errors | 🟢 supported | -| Events | 🟢 supported | -| File system | ⚪ coming soon | -| Globals | 🟢 supported | -| [HTTP](/workers/runtime-apis/nodejs/http/) | 🟢 supported | -| HTTP/2 | ⚪ not yet supported | -| [HTTPS](/workers/runtime-apis/nodejs/https/) | 🟢 supported | -| Inspector | 🟢 supported via [Chrome Dev Tools integration](/workers/observability/dev-tools/) | -| [Net](/workers/runtime-apis/nodejs/net/) | 🟢 supported | -| OS | ⚪ not yet supported | -| [Path](/workers/runtime-apis/nodejs/path/) | 🟢 supported | -| Performance hooks | 🟡 partially supported | -| [Process](/workers/runtime-apis/nodejs/process/) | 🟢 supported | -| Query strings | 🟢 supported | -| [Stream](/workers/runtime-apis/nodejs/streams/) | 🟢 supported | -| [String decoder](/workers/runtime-apis/nodejs/string-decoder/) | 🟢 supported | -| [Timers](/workers/runtime-apis/nodejs/timers/) | 🟢 supported | -| [TLS/SSL](/workers/runtime-apis/nodejs/tls/) | 🟡 partially supported | -| UDP/datagram | ⚪ not yet supported | -| [URL](/workers/runtime-apis/nodejs/url/) | 🟢 supported | -| [Utilities](/workers/runtime-apis/nodejs/util/) | 🟢 supported | -| Web Crypto API | 🟢 supported | -| Web Streams API | 🟢 supported | -| [Zlib](/workers/runtime-apis/nodejs/zlib/) | 🟢 supported | +| API Name | Natively supported by the Workers Runtime | +| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | +| [Assertion testing](/workers/runtime-apis/nodejs/assert/) | 🟢 supported | +| [Asynchronous context tracking](/workers/runtime-apis/nodejs/asynclocalstorage/) | 🟢 supported | +| [Buffer](/workers/runtime-apis/nodejs/buffer/) | 🟢 supported | +| Console | 🟢 supported | +| [Crypto](/workers/runtime-apis/nodejs/crypto/) | 🟢 supported | +| [Debugger](/workers/observability/dev-tools/) | 🟢 supported via [Chrome Dev Tools integration](/workers/observability/dev-tools/) | +| [Diagnostics Channel](/workers/runtime-apis/nodejs/diagnostics-channel/) | 🟢 supported | +| [DNS](/workers/runtime-apis/nodejs/dns/) | 🟢 supported | +| Errors | 🟢 supported | +| Events | 🟢 supported | +| File system | 🟢 supported | +| Globals | 🟢 supported | +| [HTTP](/workers/runtime-apis/nodejs/http/) | 🟢 supported | +| HTTP/2 | ⚪ not yet supported | +| [HTTPS](/workers/runtime-apis/nodejs/https/) | 🟢 supported | +| Inspector | 🟢 supported via [Chrome Dev Tools integration](/workers/observability/dev-tools/) | +| [Net](/workers/runtime-apis/nodejs/net/) | 🟢 supported | +| OS | ⚪ not yet supported | +| [Path](/workers/runtime-apis/nodejs/path/) | 🟢 supported | +| Performance hooks | 🟡 partially supported | +| [Process](/workers/runtime-apis/nodejs/process/) | 🟢 supported | +| Query strings | 🟢 supported | +| [Stream](/workers/runtime-apis/nodejs/streams/) | 🟢 supported | +| [String decoder](/workers/runtime-apis/nodejs/string-decoder/) | 🟢 supported | +| [Timers](/workers/runtime-apis/nodejs/timers/) | 🟢 supported | +| [TLS/SSL](/workers/runtime-apis/nodejs/tls/) | 🟡 partially supported | +| UDP/datagram | ⚪ not yet supported | +| [URL](/workers/runtime-apis/nodejs/url/) | 🟢 supported | +| [Utilities](/workers/runtime-apis/nodejs/util/) | 🟢 supported | +| Web Crypto API | 🟢 supported | +| Web Streams API | 🟢 supported | +| [Zlib](/workers/runtime-apis/nodejs/zlib/) | 🟢 supported | Unless otherwise specified, native implementations of Node.js APIs in Workers are intended to match the implementation in the [Current release of Node.js](https://github.com/nodejs/release#release-schedule). diff --git a/src/content/docs/workers/runtime-apis/web-standards.mdx b/src/content/docs/workers/runtime-apis/web-standards.mdx index b8a9560271e0bd5..87863bdc4a89985 100644 --- a/src/content/docs/workers/runtime-apis/web-standards.mdx +++ b/src/content/docs/workers/runtime-apis/web-standards.mdx @@ -5,27 +5,24 @@ head: - tag: title content: JavaScript and web standards description: Standardized APIs for use by Workers running on Cloudflare's global network. - --- -*** - ## JavaScript standards The Cloudflare Workers runtime is [built on top of the V8 JavaScript and WebAssembly engine](/workers/reference/how-workers-works/). The Workers runtime is updated at least once a week, to at least the version of V8 that is currently used by Google Chrome's stable release. This means you can safely use the latest JavaScript features, with no need for transpilers. All of the [standard built-in objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference) supported by the current Google Chrome stable release are supported, with a few notable exceptions: -* For security reasons, the following are not allowed: - * `eval()` - * `new Function` - * [`WebAssembly.compile`](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/compile_static) - * [`WebAssembly.compileStreaming`](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/compileStreaming_static) - * `WebAssembly.instantiate` with a [buffer parameter](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiate_static#primary_overload_%E2%80%94_taking_wasm_binary_code) - * [`WebAssembly.instantiateStreaming`](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiateStreaming_static) -* `Date.now()` returns the time of the last I/O; it does not advance during code execution. +- For security reasons, the following are not allowed: + - `eval()` + - `new Function` + - [`WebAssembly.compile`](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/compile_static) + - [`WebAssembly.compileStreaming`](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/compileStreaming_static) + - `WebAssembly.instantiate` with a [buffer parameter](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiate_static#primary_overload_%E2%80%94_taking_wasm_binary_code) + - [`WebAssembly.instantiateStreaming`](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiateStreaming_static) +- `Date.now()` returns the time of the last I/O; it does not advance during code execution. -*** +--- ## Web standards and global APIs @@ -33,57 +30,39 @@ The following methods are available per the [Worker Global Scope](https://develo ### Base64 utility methods +- atob() + - Decodes a string of data which has been encoded using base-64 encoding. - -* atob() - - * Decodes a string of data which has been encoded using base-64 encoding. - -* btoa() - - * Creates a base-64 encoded ASCII string from a string of binary data. - - +- btoa() + - Creates a base-64 encoded ASCII string from a string of binary data. ### Timers +- setInterval() + - Schedules a function to execute every time a given number of milliseconds elapses. +- clearInterval() + - Cancels the repeated execution set using [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval). -* setInterval() - - * Schedules a function to execute every time a given number of milliseconds elapses. - -* clearInterval() - - * Cancels the repeated execution set using [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval). - -* setTimeout() - - * Schedules a function to execute in a given amount of time. - -* clearTimeout() - - * Cancels the delayed execution set using [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout). - +- setTimeout() + - Schedules a function to execute in a given amount of time. +- clearTimeout() + - Cancels the delayed execution set using [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout). :::note - Timers are only available inside of [the Request Context](/workers/runtime-apis/request/#the-request-context). - ::: ### `performance.timeOrigin` and `performance.now()` -* performance.timeOrigin - - * Returns the high resolution time origin. Workers uses the UNIX epoch as the time origin, meaning that `performance.timeOrigin` will always return `0`. - -* performance.now() +- performance.timeOrigin + - Returns the high resolution time origin. Workers uses the UNIX epoch as the time origin, meaning that `performance.timeOrigin` will always return `0`. - * Returns a `DOMHighResTimeStamp` representing the number of milliseconds elapsed since `performance.timeOrigin`. Note that Workers intentionally reduces the precision of `performance.now()` such that it returns the time of the last I/O and does not advance during code execution. Effectively, because of this, and because `performance.timeOrigin` is always, `0`, `performance.now()` will always equal `Date.now()`, yielding a consistent view of the passage of time within a Worker. +- performance.now() + - Returns a `DOMHighResTimeStamp` representing the number of milliseconds elapsed since `performance.timeOrigin`. Note that Workers intentionally reduces the precision of `performance.now()` such that it returns the time of the last I/O and does not advance during code execution. Effectively, because of this, and because `performance.timeOrigin` is always, `0`, `performance.now()` will always equal `Date.now()`, yielding a consistent view of the passage of time within a Worker. ### `EventTarget` and `Event` @@ -95,23 +74,16 @@ The [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortCo ### Fetch global - - -* fetch() - - * Starts the process of fetching a resource from the network. Refer to [Fetch API](/workers/runtime-apis/fetch/). - - +- fetch() + - Starts the process of fetching a resource from the network. Refer to [Fetch API](/workers/runtime-apis/fetch/). :::note - The Fetch API is only available inside of [the Request Context](/workers/runtime-apis/request/#the-request-context). - ::: -*** +--- ## Encoding API @@ -121,7 +93,7 @@ Both `TextEncoder` and `TextDecoder` support UTF-8 encoding/decoding. The [`TextEncoderStream`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoderStream) and [`TextDecoderStream`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoderStream) classes are also available. -*** +--- ## URL API @@ -131,15 +103,13 @@ The URL API supports URLs conforming to HTTP and HTTPS schemes. :::note - The default URL class behavior differs from the URL Spec documented above. A new spec-compliant implementation of the URL class can be enabled using the `url_standard` [compatibility flag](/workers/configuration/compatibility-flags/). - ::: -*** +--- ## Compression Streams @@ -147,7 +117,7 @@ The `CompressionStream` and `DecompressionStream` classes support the deflate, d [Refer to the MDN documentation for more information](https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API) -*** +--- ## URLPattern API @@ -155,7 +125,7 @@ The `URLPattern` API provides a mechanism for matching URLs based on a convenien [Refer to the MDN documentation for more information](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern). -*** +--- ## `Intl` @@ -163,7 +133,7 @@ The `Intl` API allows you to format dates, times, numbers, and more to the forma [Refer to the MDN documentation for more information](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl). -*** +--- ## `navigator.userAgent` @@ -176,18 +146,18 @@ The [`unhandledrejection`](https://developer.mozilla.org/en-US/docs/Web/API/Wind The [`rejectionhandled`](https://developer.mozilla.org/en-US/docs/Web/API/Window/rejectionhandled_event) event is emitted by the global scope when a JavaScript promise rejection is handled late (after a rejection handler is attached to the promise after an `unhandledrejection` event has already been emitted). ```js title="worker.js" -addEventListener('unhandledrejection', (event) => { - console.log(event.promise); // The promise that was rejected. - console.log(event.reason); // The value or Error with which the promise was rejected. +addEventListener("unhandledrejection", (event) => { + console.log(event.promise); // The promise that was rejected. + console.log(event.reason); // The value or Error with which the promise was rejected. }); -addEventListener('rejectionhandled', (event) => { - console.log(event.promise); // The promise that was rejected. - console.log(event.reason); // The value or Error with which the promise was rejected. +addEventListener("rejectionhandled", (event) => { + console.log(event.promise); // The promise that was rejected. + console.log(event.reason); // The value or Error with which the promise was rejected. }); ``` -*** +--- ## `navigator.sendBeacon(url[, data])` @@ -196,12 +166,39 @@ When the [`global_navigator`](/workers/configuration/compatibility-flags/#global For example, you can replace: ```js -const promise = fetch('https://example.com', { method: 'POST', body: 'hello world' }); +const promise = fetch("https://example.com", { + method: "POST", + body: "hello world", +}); ctx.waitUntil(promise); ``` with `navigator.sendBeacon(...)`: ```js -navigator.sendBeacon('https://example.com', 'hello world'); +navigator.sendBeacon("https://example.com", "hello world"); ``` + +## The Web File System Access API + +When the `enable_web_file_system` compatibility flag is set, Workers supports the [Web File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API), which allows you to read and write files and directories to a virtual file system within the Worker environment. This API provides access to the same in-memory virtual file system as the [`node:fs` module](/workers/runtime-apis/nodejs/fs/) but does not require Node.js compatibility to be enabled. + +```js +const root = await navigator.storage.getDirctory(); + +export default { + async fetch(request) { + const fileHandle = await root.getFileHandle("hello.txt", { create: true }); + const writable = await fileHandle.createWritable(); + await writable.write("Hello, world!"); + await writable.close(); + + const file = await fileHandle.getFile(); + const contents = await file.text(); + + return new Response(contents, { status: 200 }); + }, +}; +``` + +Please refer to the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) for more information on using this API, and to the [`node:fs` documentation](/workers/runtime-apis/nodejs/fs/) for details on the virtual file system structure and limitations. diff --git a/src/content/release-notes/workers.yaml b/src/content/release-notes/workers.yaml index c48cce4370ecd6e..85b62db4f962050 100644 --- a/src/content/release-notes/workers.yaml +++ b/src/content/release-notes/workers.yaml @@ -6,6 +6,9 @@ entries: - publish_date: "2025-09-18" description: |- - Updated v8 to version 14.1. + - publish_date: "2025-09-11" + description: |- + - The node:fs and Web File System APIs are now available within Workers. - publish_date: "2025-08-21" description: |- - Updated v8 to version 14.0.