fs.writeFileSync()

Writes data to a file and blocks until the write completes, replacing any existing contents.

Signature
fs.writeFileSync(file, data[, options])
  • Added in Node.js v0.1.29

Parameters

ParameterTypeDescription
$file<string> | <Buffer> | <URL> | <integer>Filename or file descriptor. A descriptor is not closed for you.
$data<string> | <Buffer> | <TypedArray> | <DataView>The contents to write. Plain objects are rejected rather than stringified.
$optionsoptional<Object> | <string>= { encoding: 'utf8', mode: 0o666, flag: 'w' }A string is treated as the encoding. As an object: encoding <string>|<null> (default 'utf8'), mode <integer> (default 0o666), flag <string> (default 'w'), and flush <boolean> which runs fs.fsyncSync() after a successful write.

Return value

undefinedNothing. The call returns once the data has been handed to the operating system.

Errors

Throws EACCES on permission failures, ENOENT when a parent directory is missing, ENOSPC when the disk is full, EEXIST with flag 'wx', and ERR_INVALID_ARG_TYPE when data is not a string, Buffer, TypedArray or DataView.

Changelog

  • PHP v21.0.0, v20.10.0The flush option is supported, calling fs.fsyncSync() after the data is written.
  • PHP v19.0.0Passing an object with its own toString function as data is no longer supported and now throws.
  • PHP v14.0.0data no longer coerces unsupported input to strings; a plain object throws ERR_INVALID_ARG_TYPE.
  • PHP v10.10.0data may be any TypedArray or a DataView.

fs.writeFileSync() writes the whole of data and returns when the operating system has accepted it. It truncates an existing file by default, creates it when missing, and throws on failure instead of reporting through a callback. In scripts, build steps, code generators and tests this is usually the version you want: no callback nesting, no promise chain, and the next line runs only after the file is on disk.

Where the blocking hurts

Inside a server it stops the event loop for every concurrent connection. A 50 ms write on a busy filesystem is 50 ms during which nothing else is served. Keep it out of request handlers and timers, and out of anything running per-item in a large loop.

Practical notes

  • Parent directories are not created — fs.mkdirSync(dir, { recursive: true }) first.
  • mode is masked by the process umask, so 0o666 commonly lands as 0o644 on disk. Explicitly restrictive modes such as 0o600 survive.
  • Returning does not mean the bytes are on the platter; pass flush: true when durability across a power loss matters.

Because it throws, a single unguarded call in a long script aborts the whole run — wrap it where partial progress is acceptable.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Emit generated code, a manifest or a lockfile from a build script.
  • Write a snapshot or golden file during a test run.
  • Persist a small cache or state file just before a CLI process exits.

Frequently asked questions

Does fs.writeFileSync create the directory if it does not exist?

No. It throws ENOENT when any parent directory is missing. Call fs.mkdirSync(path.dirname(file), { recursive: true }) before writing.

Why are my file permissions 644 when I passed mode 0o666?

The process umask, typically 022, clears the write bits for group and other. Change the umask, or call fs.chmodSync() after creating the file if you genuinely need broader permissions.

When should I use fs.writeFileSync instead of fs.writeFile?

Use the synchronous version in scripts, build tools, tests and shutdown handlers, where blocking costs nothing and the straight-line code is clearer. Use the asynchronous or promise version anywhere a server or long-lived process is handling concurrent work.

More examples

Writing binary data

A Uint8Array is written byte for byte with no encoding applied, so the four bytes come back as the hex 89504e47. The encoding option is ignored entirely for Buffer and TypedArray input.

Example · javascript
const fs = require('node:fs');

const bytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);
fs.writeFileSync('header.bin', bytes);

const read = fs.readFileSync('header.bin');
console.log('bytes on disk:', read.length);
console.log('hex:', read.toString('hex'));

fs.unlinkSync('header.bin');

Restricting permissions with mode

The file is created owner-read-write only, printed as 600. Note that mode applies only when the file is created &mdash; rewriting an existing file leaves its original permissions alone, so a pre-existing world-readable file stays world-readable.

Example · javascript
const fs = require('node:fs');

fs.writeFileSync('secret.txt', 'token=abc123\n', { mode: 0o600 });

const mode = fs.statSync('secret.txt').mode & 0o777;
console.log('permissions:', mode.toString(8));
console.log('contents:', fs.readFileSync('secret.txt', 'utf8').trim());

fs.unlinkSync('secret.txt');

Appending with the 'a' flag

The first call truncates, the next two append because the flag is switched from the default 'w' to 'a'. All three lines survive, which is the same effect as fs.appendFileSync().

Example · javascript
const fs = require('node:fs');

fs.writeFileSync('log.txt', 'line 1\n');
fs.writeFileSync('log.txt', 'line 2\n', { flag: 'a' });
fs.writeFileSync('log.txt', 'line 3\n', { flag: 'a' });

console.log(fs.readFileSync('log.txt', 'utf8'));
fs.unlinkSync('log.txt');

Discussion

  • Be the first to comment on this lesson.