Sync vs Async fs

When Blocking Is OK — and When It Isn't

Sync vs Async fs

Sync fs methods block the event loop. Use them in scripts and at startup, never in a request handler.

3 min read Level 2/5 #nodejs#fs#sync
What you'll learn
  • Recognize the *Sync suffix
  • Know when blocking is fine
  • Avoid blocking the event loop

fs.readFileSync(path) returns the contents immediately. But while it’s reading, nothing else in your process happens — the event loop is paused.

Sync API

import { readFileSync, writeFileSync } from "node:fs";

const text = readFileSync("config.json", "utf8");
const data = JSON.parse(text);

writeFileSync("processed.json", JSON.stringify(data));

Simple, but blocking.

The Cost

Imagine a web server. A request comes in. Your handler calls readFileSync("big.csv"). While it reads — could be milliseconds, could be seconds — no other requests are processed. Every client sits waiting.

The async equivalent yields control back to the event loop. Other requests get serviced concurrently.

When Sync Is Fine

  • CLI scripts that run once and exit
  • Build tools that read configs on startup
  • Server startup code — load config, env, certs before binding the port
// server.mjs — startup code, runs once
import { readFileSync } from "node:fs";
const config = JSON.parse(readFileSync("config.json", "utf8"));

// server bound below; sync was OK because we hadn't started serving
http.createServer((req, res) => {
  // ...async from here on
}).listen(config.port);

When Sync Is Wrong

  • Inside request handlers
  • Inside loops that handle many items
  • Anywhere latency matters

A Concrete Test

// blocks for ~3 seconds — try it
const start = Date.now();
readFileSync("very-big-file.bin");
console.log(`Took ${Date.now() - start}ms`);

If you ran this in a request handler under load, every concurrent request waits 3 seconds. Bad.

The Rule of Thumb

In server code: never *Sync. In a one-off script: knock yourself out.

Promise-based fs →