The fs module, sync vs async variants, path.join and path.resolve, process.env and process.argv — reading from and writing to the real world.
Module F-3 — Working with Files, Paths, and the Environment
What this module covers: The moment you write a server, a script, or a CLI tool, you need to read files, write logs, parse paths, and pull configuration from the environment. This module covers Node.js's
fsmodule for file I/O, thepathmodule for platform-safe path manipulation, and theprocessobject for environment variables and command-line arguments. These three are in practically every Node.js program you will ever write.
The fs Module
The fs (file system) module is how Node.js reads and writes files on disk. Every operation comes in two flavours: synchronous (blocks until complete) and asynchronous (non-blocking, uses a callback or Promise). We'll cover when to use each.
Reading a File
Async with callback (old style — you will see this in legacy code):
The callback receives two arguments by convention: err first, then the result. If err is not null, something went wrong. This error-first callback pattern is a Node.js convention you will see everywhere in older code.
A gotcha worth flagging early: in the example above, the second argument to fs.readFile() is 'utf8' — the encoding. If you leave that argument out, Node.js does not give you a string at all; it gives you a raw Buffer (a chunk of binary data). Forgetting the encoding is one of the most common beginner mistakes with fs — you console.log() what you expect to be text and instead see something like <Buffer 68 65 6c 6c 6f>. Always pass 'utf8' explicitly when you want a string back.
A limit worth knowing: fs.readFile() (in any of its forms — callback, Promise, or sync) reads the entire file into memory before your callback runs or your await resolves. For a config file or a small log, that's fine. For a multi-gigabyte file, it isn't — you'll either exhaust memory or wait far longer than necessary before processing the first byte. When files get large, the right tool is a stream, which processes data in chunks as it arrives instead of loading it all at once. Streams are covered in depth in Phase 2.
Async with Promises (modern style — use this):
node:fs/promises is the Promise-based version of the fs module, available since Node.js 14. Always prefer this in new code — it works with async/await and avoids callback nesting.
Synchronous (avoid in servers, fine in scripts):
readFileSync blocks the entire Node.js process until the file is read. In a script that runs once and exits, this is fine. In a server handling concurrent requests, never use it — you will block every other request while one request waits for a file read.
Writing a File
Common flags:
'w'— write (creates or overwrites)'a'— append (creates or adds to end)'wx'— write, but fail if file already exists (useful for "create once" files)
Checking if a File Exists
Avoid the old fs.existsSync() pattern. It creates a race condition: by the time you act on the result (open the file), another process may have deleted it. The correct pattern is to attempt the operation and handle the error — exactly what try/catch around fs.access does.
Creating Directories
Listing Directory Contents
Deleting Files and Directories
Renaming and Moving Files
Getting File Metadata
The path Module
File paths are one of the most common sources of bugs in cross-platform code. On Windows, paths use backslashes (C:\Users\jatin). On macOS and Linux, they use forward slashes (/home/jatin). The path module abstracts this so your code works everywhere.
Sign in to keep reading
The rest of this module is free — sign in with Google to unlock it and track your progress.
Sign in & RegisterDiscussion
0Join the discussion