How to Use writeFile in Node.js: A Complete Guide to Writing Files
Use fs.writeFile() for asynchronous file writing, fs.writeFileSync() for synchronous operations, or fs.promises.writeFile() for promise-based async workflows in Node.js.
The writefile in node js workflow is fundamental to server-side JavaScript development. According to the nodejs/node source code, the file system module provides three distinct APIs for writing data to disk—each optimized for different concurrency and error-handling patterns. This guide examines the actual implementation in lib/fs.js and lib/internal/fs/promises.js to show you exactly how to use each variant.
Understanding the writeFile API in Node.js
Node.js exposes file writing capabilities through three primary interfaces:
fs.writeFile(path, data, options, callback)– The traditional callback-based asynchronous method defined inlib/fs.js(lines 2326–2456)fs.writeFileSync(path, data, options)– The synchronous blocking variant inlib/fs.js(lines 2378–2398)fs.promises.writeFile(path, data, options)– The modern Promise-based API implemented inlib/internal/fs/promises.js(lines 1220–1244)
All three ultimately delegate to the same C++ bindings—binding.writeFileUtf8 for string data and binding.writeBuffer for Buffer/Uint8Array instances—located in src/node_file.cc.
How to Use writeFile in Node.js: Practical Examples
Asynchronous File Writing with Callbacks
The standard writeFile method is non-blocking and accepts a callback to handle completion or errors. According to the source in lib/fs.js, it validates the path using getValidatedPath, normalizes options via validateEncoding, and allocates an FSReqCallback object for the underlying libuv thread pool.
const { writeFile } = require('fs');
writeFile('example.txt', 'Hello, Node.js!', 'utf8', (err) => {
if (err) throw err;
console.log('File written successfully');
});
Synchronous File Writing
Use writeFileSync when you need to block the event loop until the operation completes. The implementation in lib/fs.js performs the same validation steps as the async version but invokes binding.writeFileUtf8 or binding.writeBuffer directly without creating an FSReqCallback object.
const { writeFileSync } = require('fs');
try {
writeFileSync('sync.txt', Buffer.from([0x01, 0x02, 0x03]));
console.log('Sync write done');
} catch (e) {
console.error(e);
}
Promise-Based File Writing
Modern Node.js applications typically use the fs.promises API for cleaner async/await syntax. As implemented in lib/internal/fs/promises.js, this wrapper calls the callback-based writeFile and returns a Promise that resolves when the underlying FSReqCallback completes.
const { promises: fs } = require('fs');
async function save() {
await fs.writeFile('promise.txt', 'Using promises');
console.log('Promise write complete');
}
save().catch(console.error);
Writing Binary Data and Buffers
When writing binary data, Node.js bypasses string encoding entirely. If the data argument is a Buffer, Uint8Array, or similar ArrayBufferView, the source code routes the call to binding.writeBuffer instead of binding.writeFileUtf8.
const { writeFile } = require('fs');
const binary = Uint8Array.from([0xde, 0xad, 0xbe, 0xef]);
writeFile('binary.bin', binary, { encoding: 'binary' }, (err) => {
if (err) throw err;
});
Core Implementation Details of writeFile in Node.js
Understanding the internal workflow helps debug permission errors or encoding issues. According to the nodejs/node source:
- Argument Validation – The API normalizes the
optionsargument and validates the callback viavalidateFunctioninlib/internal/fs/utils.js. - Path Handling – The path passes through
getValidatedPath(supporting strings, Buffers, or URLs) and checks the Permission Model viapermission.has('fs.write', path)when enabled. - Flag Selection – The default flag is
'w'(write and truncate). Explicit flags convert to numeric codes viastringToFlagsinlib/internal/fs/utils.js. - Encoding Resolution – String data uses
validateEncodingto resolve the encoding (default'utf8') before callingbinding.writeFileUtf8. - Binding Execution – The actual I/O occurs in
src/node_file.ccviawriteFileUtf8orwriteBuffer, executed either asynchronously through anFSReqCallbackobject or synchronously depending on the API variant.
Common Flags and Options for writeFile
The options object controls how writefile in node js behaves:
flag–'w'(default) truncates the file or creates it if missing;'a'appends to existing content;'wx'fails if the file already exists.encoding–'utf8'(default),'ascii','base64','hex', or'binary'(deprecated alias for'latin1').mode– File permissions as an octal number (default0o666), masked byprocess.umask().
Summary
fs.writeFileprovides asynchronous, callback-based file writing implemented inlib/fs.js(lines 2326–2456).fs.writeFileSyncoffers synchronous blocking writes inlib/fs.js(lines 2378–2398).fs.promises.writeFiledelivers modern Promise-based async/await support fromlib/internal/fs/promises.js(lines 1220–1244).- All variants delegate to C++ bindings (
binding.writeFileUtf8orbinding.writeBuffer) insrc/node_file.ccafter validating paths, flags, and encodings. - Use
flag: 'a'to append rather than truncate, and prefer the Promise API for cleaner error handling in modern applications.
Frequently Asked Questions
What is the difference between writeFile and writeFileSync in Node.js?
writeFile executes asynchronously using the libuv thread pool and accepts a callback function to handle completion or errors, allowing the event loop to continue processing other tasks. writeFileSync blocks the entire Node.js process until the operating system confirms the write is complete, making it simpler for scripts but unsuitable for high-concurrency servers.
How do I append to a file instead of overwriting it using writeFile?
Pass { flag: 'a' } in the options argument. According to the source code in lib/fs.js, the stringToFlags utility converts 'a' to the O_APPEND flag, which instructs the C++ binding in src/node_file.cc to write at the end of the file rather than truncating existing content.
Can I use writeFile with promises instead of callbacks?
Yes. Import fs.promises or use require('fs').promises to access the Promise-based writeFile method implemented in lib/internal/fs/promises.js. This wrapper internally calls the callback-based version but returns a Promise that resolves when the underlying FSReqCallback completes, enabling cleaner async/await syntax.
What happens if the file doesn't exist when using writeFile?
If the file does not exist, writeFile creates it automatically provided the parent directory exists and the process has write permissions. The default flag: 'w' triggers this behavior in the C++ binding, which uses O_CREAT combined with O_TRUNC to ensure the file exists and is empty before writing. If the parent directory is missing, the operation throws ENOENT.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →