Writing Files
Now that you know how to read files, let's learn how to write data to files. The fs module provides several ways to create and modify files, from simple one-shot writes to streaming large amounts of data.
Writing Files Synchronously
The simplest way to write a file:
const fs = require('fs');
// Write a string to a file
fs.writeFileSync('output.txt', 'Hello, World!');
// Write with encoding specified
fs.writeFileSync('data.txt', 'Some text data', 'utf8');
// Write JSON data
const config = { port: 3000, debug: true };
fs.writeFileSync('config.json', JSON.stringify(config, null, 2));
This will:
- Create the file if it doesn't exist
- Overwrite the file if it does exist
- Block execution until complete
Writing Files with Callbacks
Non-blocking file writing:
const fs = require('fs');
fs.writeFile('output.txt', 'Hello, async world!', 'utf8', (err) => {
if (err) {
console.error('Error writing file:', err.message);
return;
}
console.log('File written successfully!');
});
console.log('This runs while file is being written...');
Writing Files with Promises
The modern async approach:
const fs = require('fs/promises');
async function saveData(filename, data) {
try {
await fs.writeFile(filename, data, 'utf8');
console.log(`Saved to ${filename}`);
} catch (err) {
console.error('Failed to save:', err.message);
}
}
// Save JSON data
async function saveConfig(config) {
const json = JSON.stringify(config, null, 2);
await fs.writeFile('config.json', json, 'utf8');
}
Appending to Files
Add content to the end of a file without overwriting:
const fs = require('fs');
// Synchronous append
fs.appendFileSync('log.txt', 'New log entry\n');
// Async append
fs.appendFile('log.txt', 'Another entry\n', (err) => {
if (err) console.error(err);
});
// Promise-based append
const fsPromises = require('fs/promises');
await fsPromises.appendFile('log.txt', 'Promise entry\n');
Write Options
The write functions accept an options object:
// Using options object
fs.writeFileSync('output.txt', 'data', {
encoding: 'utf8', // Character encoding
mode: 0o644, // File permissions (Unix)
flag: 'w' // Write mode
});
// Common flags
// 'w' - Write (default), create if doesn't exist, truncate if exists
// 'a' - Append, create if doesn't exist
// 'wx' - Write, fail if file exists (exclusive)
// 'ax' - Append, fail if file exists
// 'r+' - Read and write, file must exist
// Example: Only create new file, don't overwrite
try {
fs.writeFileSync('unique.txt', 'data', { flag: 'wx' });
console.log('File created');
} catch (err) {
if (err.code === 'EEXIST') {
console.log('File already exists');
}
}
Writing JSON Files
A common pattern for saving structured data:
const fs = require('fs');
// Save object as JSON
function saveJSON(filename, data) {
const json = JSON.stringify(data, null, 2);
fs.writeFileSync(filename, json, 'utf8');
}
// Load and modify JSON
function updateJSON(filename, updates) {
const data = JSON.parse(fs.readFileSync(filename, 'utf8'));
Object.assign(data, updates);
saveJSON(filename, data);
return data;
}
// Example usage
const config = { version: '1.0', debug: false };
saveJSON('config.json', config);
const updated = updateJSON('config.json', { debug: true });
console.log(updated); // { version: '1.0', debug: true }
Writing Streams for Large Data
For large files or continuous data:
const fs = require('fs');
// Create a write stream
const stream = fs.createWriteStream('large-output.txt');
// Write chunks of data
stream.write('Line 1\n');
stream.write('Line 2\n');
stream.write('Line 3\n');
// End the stream
stream.end('Final line\n');
// Handle events
stream.on('finish', () => {
console.log('All data written');
});
stream.on('error', (err) => {
console.error('Write error:', err);
});
Generating Large Files
const fs = require('fs');
const stream = fs.createWriteStream('big-file.csv');
// Write header
stream.write('id,name,value\n');
// Write 1 million rows
for (let i = 0; i < 1000000; i++) {
stream.write(`${i},item${i},${Math.random()}\n`);
}
stream.end();
Copying Files
Several ways to copy files:
const fs = require('fs');
// Method 1: Read then write (simple, uses memory)
const content = fs.readFileSync('source.txt');
fs.writeFileSync('destination.txt', content);
// Method 2: Built-in copy (Node.js 16+)
fs.copyFileSync('source.txt', 'destination.txt');
// Method 3: Streams (best for large files)
const readStream = fs.createReadStream('source.txt');
const writeStream = fs.createWriteStream('destination.txt');
readStream.pipe(writeStream);
// Method 4: Async copy
const fsPromises = require('fs/promises');
await fsPromises.copyFile('source.txt', 'destination.txt');
Atomic Writes
For critical data, write to a temp file first:
const fs = require('fs');
const path = require('path');
function atomicWriteSync(filepath, data) {
// Write to temp file first
const tempPath = filepath + '.tmp';
fs.writeFileSync(tempPath, data, 'utf8');
// Rename temp to target (atomic on most systems)
fs.renameSync(tempPath, filepath);
}
// This ensures file isn't corrupted if process crashes mid-write
atomicWriteSync('important-data.json', JSON.stringify(data));
Common Patterns
Write with Backup
function writeWithBackup(filepath, data) {
// Create backup of existing file
if (fs.existsSync(filepath)) {
fs.copyFileSync(filepath, filepath + '.bak');
}
// Write new data
fs.writeFileSync(filepath, data);
}
Pretty-Print JSON
function savePrettyJSON(filepath, data) {
// null replacer, 2 spaces for indent
const pretty = JSON.stringify(data, null, 2);
fs.writeFileSync(filepath, pretty);
}
Create Log Entry
function logToFile(message) {
const timestamp = new Date().toISOString();
const entry = `[${timestamp}] ${message}\n`;
fs.appendFileSync('app.log', entry);
}
Key Takeaways
- Use
writeFileSyncfor simple, blocking writes - Use
writeFilecallback or promises for async writes - Use
appendFileSync/appendFileto add to existing files - Use the
flagoption to control write behavior (w, a, wx) - Use streams for large files or continuous data
- JSON.stringify with indent (2 spaces) for readable JSON files
- Consider atomic writes for critical data
- Always handle potential errors
Summary
You've learned how to write files in Node.js using synchronous, callback, and promise-based approaches. You know how to append to files, use different write modes, and handle JSON data. For large files, streams provide memory-efficient writing. These skills are essential for logging, configuration, caching, and data persistence.
Next, we'll explore working with directories—creating, reading, and managing folder structures.

