Question
How can I write data to a file in a Node.js application? I would like to save text or other content to a file, but I have not found a working approach yet.
Short Answer
You will learn how Node.js writes files with its built-in fs module. This includes callback-based, Promise-based, synchronous, append, and JSON file-writing examples, plus practical error-handling guidance.
Concept
Node.js does not write files directly from a variable or console.log(). Instead, it uses the built-in file system module, named fs.
Writing a file involves three pieces of information:
- The path: where the file should be saved, such as
./notes.txt. - The data: the text,
Buffer, or serialized JSON to save. - An error strategy: what to do if the path is invalid, permissions are missing, or storage fails.
The modern Promise-based API is usually the clearest choice:
const fs = require('node:fs/promises');
await fs.writeFile('./notes.txt', 'Hello from Node.js!', 'utf8');
writeFile() creates the file when it does not exist. By default, it replaces all existing contents when the file already exists.
File writing is important for scripts that generate reports, export data, save application settings, create logs, or process uploaded content. Because disk operations can take time, Node.js commonly uses asynchronous APIs so other work can continue while the operating system writes the file.
Mental Model
Think of a file path as a street address and file data as a package.
./notes.txttells Node.js where to deliver the package.'Hello'is what goes into the package.writeFile()is the delivery service.
If a package is delivered to an address that already has a package, writeFile() normally removes the old one and leaves the new one. If you want to add another package without removing the first, use appendFile() instead.
Syntax and Examples
Use the Promise-based fs API with async/await:
const fs = require('node:fs/promises');
async function saveMessage() {
try {
await fs.writeFile('./message.txt', 'Hello, file system!\n', 'utf8');
console.log('File saved successfully.');
} catch (error) {
console.error('Could not save the file:', error.message);
}
}
saveMessage();
fs.writeFile(path, data, encoding) accepts:
path: a string such as'./message.txt'data: text, aBuffer, or other supported binary dataencoding: use when writing normal text
Step by Step Execution
Consider this code:
const fs = require('node:fs/promises');
async function createReport() {
const report = 'Users: 24\nActive users: 18\n';
await fs.writeFile('./report.txt', report, 'utf8');
console.log('Report created');
}
createReport().catch(console.error);
Execution flow:
require('node:fs/promises')loads Node.js's Promise-based file system functions.createReport()is called and starts running.- The
reportvariable stores a string containing two lines.\nmeans a new line. fs.writeFile()asks the operating system to write that string toreport.txtin the current working directory.awaitpauses this async function until writing succeeds or fails; it does not block Node.js from handling other asynchronous work.
Real World Use Cases
Common uses of file writing include:
- Report generation: create CSV, text, or JSON reports from database data.
- Configuration tools: save local settings, feature flags, or development configuration.
- Build scripts: generate source files, manifests, documentation, or static assets.
- Data exports: let an administrator export users, orders, or analytics as a downloadable file.
- Command-line tools: save processed images, converted data, or command output.
- Logging: append application events to a log file, usually with a logging library in larger services.
For example, a script can save a CSV export:
const fs = require('node:fs/promises');
const csv = 'name,email\nAda,ada@example.com\nLinus,linus@example.com\n';
fs.writeFile('./users.csv', csv, 'utf8')
.then(() => console.log('CSV exported'))
.catch(console.error);
Real Codebase Usage
In production code, developers usually make file writing predictable and safe.
Build paths explicitly
Avoid depending on whichever directory happened to start the process. Use path.join() and, where appropriate, a known application directory.
const path = require('node:path');
const fs = require('node:fs/promises');
const outputPath = path.join(process.cwd(), 'output', 'report.txt');
Create parent directories first
writeFile() creates the file, but it does not create missing parent folders.
await fs.mkdir(path.dirname(outputPath), { recursive: true });
await fs.writeFile(outputPath, 'Report data', 'utf8');
Validate data before saving
A guard clause prevents writing invalid content.
async () {
(!user?.) {
();
}
fs.(, .(user, , ), );
}
Common Mistakes
Forgetting to wait for an asynchronous write
This code starts the write but immediately prints the success message:
// Problematic
fs.writeFile('./note.txt', 'Hello');
console.log('Saved');
Use await inside an async function, or use .then()/.catch():
await fs.writeFile('./note.txt', 'Hello', 'utf8');
console.log('Saved');
Assuming writeFile() appends
await fs.writeFile('./log.txt', 'First line\n', 'utf8');
await fs.writeFile('./log.txt', 'Second line\n', );
Comparisons
| Method | Behavior | Best use |
|---|---|---|
fs.writeFile() | Asynchronously creates or replaces a file | Normal application and server code |
fs.appendFile() | Asynchronously adds data to the end of a file | Logs or incremental text output |
fs.writeFileSync() | Creates or replaces a file while blocking execution | Small scripts, setup code, simple tooling |
fs.createWriteStream() | Writes data in chunks | Large files or continuous output |
Callback API vs Promise API
| Style | Example | Notes |
|---|---|---|
Cheat Sheet
const fs = require('node:fs/promises');
| Task | Code |
|---|---|
| Write or replace text | await fs.writeFile('./file.txt', 'Text', 'utf8') |
| Append text | await fs.appendFile('./file.txt', 'More text\n', 'utf8') |
| Write formatted JSON | await fs.writeFile('./data.json', JSON.stringify(data, null, 2), 'utf8') |
| Create a folder | await fs.mkdir('./output', { recursive: true }) |
| Handle an error | try { await ... } catch (error) { ... } |
Key rules:
writeFile()overwrites an existing file by default.- Parent directories must already exist unless you create them with
mkdir().
FAQ
Does fs.writeFile() create a file if it does not exist?
Yes. It creates the file when its parent directory already exists.
Does fs.writeFile() overwrite an existing file?
Yes. Its default behavior is to replace the file's existing contents. Use fs.appendFile() to add content instead.
How do I write JSON to a file in Node.js?
Convert the value using JSON.stringify(value, null, 2), then pass that string to writeFile().
Why do I get an ENOENT error when writing a file?
Usually, part of the path does not exist. Create the parent directory with await fs.mkdir(directory, { recursive: true }).
Should I use writeFileSync() or writeFile()?
Prefer asynchronous writeFile() in applications and servers. Use writeFileSync() only when blocking execution is acceptable, such as a short one-time script.
Can I write a file using require('fs') instead of require('node:fs/promises')?
Mini Project
Description
Build a small report exporter that saves a list of tasks to a formatted JSON file. This mirrors a common backend or command-line task: turning in-memory application data into a file that another person or system can use.
Goal
Create an output/tasks.json file containing a formatted JSON task report.
Requirements
Create an array containing at least three task objects.
Create an output directory if it is missing.
Save the task data as readable JSON in output/tasks.json.
Display a success message that includes the saved file path.
Handle file-writing errors without crashing silently.
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.