Open-Source Wikis

/

Node.js

/

Systems

/

File system

nodejs/node

File system

Purpose

Implement the node:fs module: callback, Promise, and synchronous variants of POSIX-style file APIs, plus higher-level pieces like createReadStream, createWriteStream, Dir, glob, cp, and the fsPromises namespace. Built on libuv's uv_fs_* request layer.

Directory layout

lib/
  fs.js                              // public callback + sync API
  fs/
    promises.js                      // public Promise API (re-export)
  internal/fs/
    promises.js                      // fsPromises implementation
    streams.js                       // ReadStream / WriteStream
    dir.js                           // fs.Dir (async iterator over a directory)
    glob.js                          // fs.glob / fsPromises.glob
    cp/                              // recursive copy implementation
    rimraf.js                        // recursive remove
    read_file_context.js             // chunked readFile
    read/                            // streaming read helpers
    sync_write_stream.js             // SyncWriteStream (used for stdout fallback)
    utils.js                         // shared FS helpers and option parsers
    watchers.js                      // fs.watch / fs.watchFile
    recursive_watch.js               // watch-recursive on platforms without native support
    observer/                        // FSWatcher abstractions
src/
  node_file.{cc,h}                   // FSReqWrap, fs.* binding
  node_file-inl.h
  node_file_utils.{cc,h}             // shared helpers
  node_dir.{cc,h}                    // fs.opendir
  node_stat_watcher.{cc,h}           // fs.watchFile poller
  fs_event_wrap.cc                   // libuv fs_event_t wrapper

Key abstractions

Type / file Role
FSReqCallback (src/node_file.cc) ReqWrap-derived request used by callback APIs.
FSReqPromise (src/node_file.cc) Promise variant, resolves a JS Promise when libuv finishes.
Binding (src/node_file.cc) All of internalBinding('fs')open, read, writeBuffer, stat, mkdir, etc.
ReadStream (lib/internal/fs/streams.js) Readable backed by fs.read/uv_fs_read.
WriteStream (lib/internal/fs/streams.js) Writable backed by fs.write/uv_fs_write.
FileHandle (lib/internal/fs/promises.js) Promise-based wrapper around an open fd.
Dir (lib/internal/fs/dir.js) Iterator backed by uv_fs_opendir/readdir.
FSWatcher (lib/internal/fs/watchers.js) Event watcher on top of fs_event_t.
StatWatcher (src/node_stat_watcher.cc) Polling-based fs.watchFile.

How a callback fs.readFile flows

sequenceDiagram
    participant JS as fs.readFile(path, cb)
    participant InternalFS as lib/fs.js
    participant Bind as internalBinding('fs')
    participant Cpp as FSReqCallback
    participant uv as libuv (uv_fs_open/read)
    participant Loop as event loop

    JS->>InternalFS: validate args, create context
    InternalFS->>Bind: open(path, flags, mode, req)
    Bind->>Cpp: schedule uv_fs_open
    Cpp->>uv: uv_fs_open
    uv->>Loop: dispatch to threadpool
    Loop-->>Cpp: completion
    Cpp-->>InternalFS: oncomplete(fd) → readNextChunk
    InternalFS->>Bind: read(fd, buffer, offset, length, position, req)
    Bind->>uv: uv_fs_read
    uv-->>Cpp: completion
    Cpp-->>InternalFS: oncomplete → maybe more reads
    InternalFS-->>JS: cb(null, contents)

fs.readFile does not actually read in a single uv request — it loops with chunked reads (read_file_context.js) so it can stream into a single buffer when stat is unreliable (sockets, pipes, /dev/...).

Promise vs. callback vs. sync

  • fs.X(...) — callback, free of allocations on the JS side beyond the request.
  • fs.XSync(...) — synchronous; uses uv_fs_* with the loop set to do its work synchronously. Allocations are minimal but blocks the loop.
  • fs.promises.X(...) — Promise; backed by FSReqPromise which resolves the V8 promise from C++. The FileHandle API (fs.promises.open) is the canonical way to operate on an fd in Promise land.

Watchers

Two implementations:

  • fs.watch(path, opts, cb)FSWatcher over uv_fs_event_t (src/fs_event_wrap.cc). Recursive watch on Windows/macOS uses native; on Linux it uses lib/internal/fs/recursive_watch.js to walk subtrees.
  • fs.watchFile(path, opts, cb)StatWatcher, a uv_timer_t plus uv_fs_stat (src/node_stat_watcher.cc). Polling, used when event watchers aren't available or aren't desired.

Streams

fs.createReadStream(path, opts) returns a ReadStream (Readable) that opens once, then loops read(fd, …) filling its buffer. fs.createWriteStream(path, opts) mirrors that with write + close. The Promise namespace exposes FileHandle.createReadStream / createWriteStream that operate on a pre-open FileHandle.

Glob

fs.glob (Node 22+) / fsPromises.glob is implemented in lib/internal/fs/glob.js using a small finite-state matcher that streams entries. Matching logic comes from deps/minimatch/. Owners: @nodejs/fs-adjacent.

Permission model

The fs permission domain (src/permission/fs_permission.cc) restricts read/write access when --permission is on. JS-side checks call process.permission.has('fs.read', path); C++ checks happen in FSReqWrap::CanAccess paths. See systems › permission-model.

Integration points

  • Streams: All read/write paths plug into lib/internal/streams/.
  • Buffers: Buffer allocation is the common output path for read calls; pooled buffers come from Buffer.allocUnsafePool.
  • Errors: libuv errors are wrapped via lib/internal/errors.js#uvException to produce Error & { code, errno, syscall, path }.
  • Workers: The libuv threadpool is shared across workers; tune size with UV_THREADPOOL_SIZE.

Entry points for modification

  • Adding an FS API? JS in lib/fs.js and lib/fs/promises.js (or under lib/internal/fs/); C++ binding in src/node_file.cc (Open, Read, …, registered in the binding init function); document at doc/api/fs.md.
  • Adding a new error mapping? Extend lib/internal/errors.js#uvException.
  • Hot-path concern? Most fs perf wins come from avoiding extra JS↔C++ trips; check the macros in src/node_file.cc (SyncCall, AsyncCall).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

File system – Node.js wiki | Factory