# How to Use writeFile in Node.js: A Complete Guide to Writing Files

> Learn to use writeFile in Node.js effectively. Explore asynchronous fs.writeFile, synchronous fs.writeFileSync, and promise-based fs.promises.writeFile for robust file handling.

- Repository: [Node.js/node](https://github.com/nodejs/node)
- Tags: how-to-guide
- Published: 2026-02-16

---

**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`](https://github.com/nodejs/node/blob/main/lib/fs.js) and [`lib/internal/fs/promises.js`](https://github.com/nodejs/node/blob/main/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 in [`lib/fs.js`](https://github.com/nodejs/node/blob/main/lib/fs.js) (lines 2326–2456)
- **`fs.writeFileSync(path, data, options)`** – The synchronous blocking variant in [`lib/fs.js`](https://github.com/nodejs/node/blob/main/lib/fs.js) (lines 2378–2398)
- **`fs.promises.writeFile(path, data, options)`** – The modern Promise-based API implemented in [`lib/internal/fs/promises.js`](https://github.com/nodejs/node/blob/main/lib/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`](https://github.com/nodejs/node/blob/main/lib/fs.js), it validates the path using `getValidatedPath`, normalizes options via `validateEncoding`, and allocates an `FSReqCallback` object for the underlying libuv thread pool.

```javascript
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`](https://github.com/nodejs/node/blob/main/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.

```javascript
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`](https://github.com/nodejs/node/blob/main/lib/internal/fs/promises.js), this wrapper calls the callback-based `writeFile` and returns a Promise that resolves when the underlying `FSReqCallback` completes.

```javascript
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`.

```javascript
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:

1. **Argument Validation** – The API normalizes the `options` argument and validates the callback via `validateFunction` in [`lib/internal/fs/utils.js`](https://github.com/nodejs/node/blob/main/lib/internal/fs/utils.js).
2. **Path Handling** – The path passes through `getValidatedPath` (supporting strings, Buffers, or URLs) and checks the Permission Model via `permission.has('fs.write', path)` when enabled.
3. **Flag Selection** – The default flag is `'w'` (write and truncate). Explicit flags convert to numeric codes via `stringToFlags` in [`lib/internal/fs/utils.js`](https://github.com/nodejs/node/blob/main/lib/internal/fs/utils.js).
4. **Encoding Resolution** – String data uses `validateEncoding` to resolve the encoding (default `'utf8'`) before calling `binding.writeFileUtf8`.
5. **Binding Execution** – The actual I/O occurs in `src/node_file.cc` via `writeFileUtf8` or `writeBuffer`, executed either asynchronously through an `FSReqCallback` object 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 (default `0o666`), masked by `process.umask()`.

## Summary

- **`fs.writeFile`** provides asynchronous, callback-based file writing implemented in [`lib/fs.js`](https://github.com/nodejs/node/blob/main/lib/fs.js) (lines 2326–2456).
- **`fs.writeFileSync`** offers synchronous blocking writes in [`lib/fs.js`](https://github.com/nodejs/node/blob/main/lib/fs.js) (lines 2378–2398).
- **`fs.promises.writeFile`** delivers modern Promise-based async/await support from [`lib/internal/fs/promises.js`](https://github.com/nodejs/node/blob/main/lib/internal/fs/promises.js) (lines 1220–1244).
- All variants delegate to C++ bindings (`binding.writeFileUtf8` or `binding.writeBuffer`) in `src/node_file.cc` after 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`](https://github.com/nodejs/node/blob/main/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`](https://github.com/nodejs/node/blob/main/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`.