fs.writeFile(path, data, callback) writes a string or Buffer to a file. If the file does not exist, Node creates it; if it does, the old contents are replaced. fs.writeFileSync(path, data) does the same and waits until the write is done, and fs.appendFile adds to the end of the file instead of replacing it.
It prints saved and then the text it read back; the callback gets only an error (or null), never the data. Pass 42 instead of the string and the call throws a TypeError: the data must be a string or a Buffer.
writeFile, writeFileSync and fs/promises
The three forms take the same arguments and differ in how you wait for the result.
const fs = require('fs');
const fsp = require('fs/promises');
fs.writeFileSync('a.txt', 'one'); // blocks, throws on error
fs.writeFile('b.txt', 'two', (err) => {}); // callback with err
await fsp.writeFile('c.txt', 'three'); // promise, use in async code
Use writeFileSync in scripts and startup code, and the promise version in servers, where a sync write blocks every other request until the disk is done. The fs/promises page shows the rest of the promise API.
Append to a file with appendFile
writeFile replaces the whole file. To add a line to a log, use appendFile, which also creates the file the first time.
The first read prints "second\n", because the second writeFileSync replaced first, and the second prints "second\nthird\nfourth\n" (JSON.stringify makes the newlines visible). Add the \n yourself: neither function adds one.
writeFile | appendFile | |
|---|---|---|
| File missing | Creates it | Creates it |
| File exists | Replaces the contents | Adds to the end |
| Default flag | 'w' | 'a' |
| Typical use | Saving a whole document or JSON | Logs, one line at a time |
Do not overwrite: the flag option
The third argument can be an options object. Its flag decides what happens to an existing file. 'wx' means "write, but fail if the file already exists", which is the safe way to create a file only once.
The second call fails with EEXIST, so the file still holds abc123. Change the second call's file name to id2.txt and both calls print created.
The flags you will meet most: 'w' (default, replace), 'a' (append), 'wx' (create only) and 'ax' (append, but only to a new file).
Checking with fs.existsSync first and then writing has a gap: another process can create the file between the check and the write. 'wx' does both in one step.
Write JSON to a file
writeFile does not accept objects. Turn them into text with JSON.stringify; the third argument, 2, indents the output so the file is readable.
The file holds the object over several indented lines, and parsing it back gives an equal object, so the last line prints 2. Pass the object without JSON.stringify and the call throws a TypeError.
Create the folder first with mkdir
writeFile creates files, not folders. Writing to reports/2026/june.txt when reports does not exist fails with ENOENT. Create the path first with mkdir and { recursive: true }, which creates every missing folder and does nothing if they already exist.
The first write fails with ENOENT; after mkdir, the same write succeeds and readdir lists [ 'june.txt' ]. Build these paths with path.join in real code so they work on Windows too.
Common mistakes
Assuming the file is written right after the call. fs.writeFile returns before the data is on disk. Read the file or start the next step inside the callback, or await the promise version.
Losing data by writing in a loop. Calling writeFile once per item replaces the file each time, leaving only the last item. Use appendFile, or build the whole string and write it once.
Writing [object Object]. Passing an object through String() or a template literal writes [object Object]. Use JSON.stringify.
Frequently Asked Questions
Does fs.writeFile overwrite the file?
Yes. With the default flag 'w' it truncates the file and writes the new data, so the old contents are gone. Pass { flag: 'a' } or use appendFile to add to the end instead.
Does fs.writeFile create the file if it does not exist?
Yes, it creates the file. It does not create missing folders, though: writing to logs/app.log when logs does not exist fails with ENOENT.
What can I pass as the data?
A string, a Buffer or a typed array. Anything else, such as an object or a number, throws a TypeError, so convert objects with JSON.stringify and numbers with String() first.
Is writeFile safe to call many times at once on the same file?
No. Two writeFile calls on one file in parallel can interleave and leave mixed contents. Wait for one to finish before starting the next, or collect the data and write once.