Files and paths in Node
Async file I/O with promises, streams for large data, and building paths that work on every platform.
Reading and writing
import { readFile, writeFile, mkdir } from "node:fs/promises";
import path from "node:path";
const file = path.join(process.cwd(), "data", "config.json");
const text = await readFile(file, "utf8");
const config = JSON.parse(text);
await mkdir(path.dirname(file), { recursive: true });
await writeFile(file, JSON.stringify(config, null, 2), "utf8");⚠️
Avoid the
*Sync variants in a server. They block the event loop for every request for the duration of the disk call, which is precisely what Node is designed to avoid.Paths done right
import path from "node:path";
import { fileURLToPath } from "node:url";
const here = path.dirname(fileURLToPath(import.meta.url));
const target = path.join(here, "..", "public", "index.html");
path.extname(target); // '.html'
path.basename(target); // 'index.html'
path.resolve("a", "b"); // absolute
path.normalize("a/../b"); // 'b'- Use
path.joinrather than string concatenation — it inserts the right separator per platform. - In ES modules there is no
__dirname; derive it fromimport.meta.url. - Never build a filesystem path from raw user input without validating it — that is path traversal.
Streams for large data
Reading a multi-gigabyte file into memory with readFile will exhaust the heap. Streams process it in chunks with constant memory.
import { createReadStream, createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
import { createGzip } from "node:zlib";
await pipeline(
createReadStream("access.log"),
createGzip(),
createWriteStream("access.log.gz")
);💡
pipeline propagates errors and destroys every stream on failure — the modern replacement for hand-wired .pipe() chains that leak on error.FAQ
Why is my write not finished when the program exits?
You did not await it. File operations are asynchronous; await the promise or the stream's
finish event.How do I watch a file for changes?
fs.watch for simple cases, or a polling approach in development containers where inotify events are unreliable.Related
Node.js: getting started Building an HTTP server
Last refreshed 2026-09-17.