Learn how to prevent EMFILE errors in Node.js. Step-by-step fixes using streams, concurrency limits, graceful-fs, and increasing file descriptor limits
If you’ve ever run a Node.js app and encountered the dreaded error:
Error: EMFILE: too many open files
It means your application has reached the system’s file descriptor limit. This usually happens when you try to open too many files, sockets, or streams simultaneously.
In this guide, we’ll cover the causes of EMFILE, common scenarios where it occurs, and step-by-step fixes.
1. What Causes “EMFILE” Errors?
Node.js relies on the operating system to manage file descriptors (FDs). These include:
-
Files (
fs.readFile
,fs.createReadStream
) - Network sockets (HTTP requests, DB connections)
- Pipes and streams
Each open file or socket consumes a file descriptor. If your code doesn’t close them properly or tries to open too many at once, you’ll hit the system limit.
2. Common Scenarios
- Reading thousands of files with
fs.readFile
in a loop - Watching too many files with
fs.watch
- Handling too many HTTP connections without limiting concurrency
- Database connections are not being closed
3. Fix 1: Use Streams Instead of readFile
Using fs.readFile
loads the entire file into memory. With many files, this quickly exhausts file descriptors.
Bad (may cause EMFILE):
const fs = require('fs');
const files = ['file1.txt', 'file2.txt', 'file3.txt'];
files.forEach(file => {
fs.readFile(file, 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
});
Good streaming
const fs = require('fs');
const stream = fs.createReadStream('largefile.txt', { encoding: 'utf8' });
stream.on('data', chunk => console.log(chunk));
stream.on('end', () => console.log('File read completed.'));
4. Fix 2: Limit Concurrency with p-limit
Instead of opening thousands of files at once, process them in batches.
Install helper:
npm install p-limit
Exampls
const fs = require('fs').promises;
const pLimit = require('p-limit');
const limit = pLimit(5); // only 5 concurrent operations
const files = Array.from({ length: 1000 }, (_, i) => `file${i}.txt`);
const tasks = files.map(file =>
limit(() => fs.readFile(file, 'utf8'))
);
Promise.all(tasks)
.then(results => console.log('All files processed'))
.catch(console.error);
This prevents Node from opening too many files at once.
5. Fix 3: Close File Descriptors
Always close file handles when done:
const fs = require('fs');
fs.open('test.txt', 'r', (err, fd) => {
if (err) throw err;
console.log('File opened');
fs.close(fd, (err) => {
if (err) throw err;
console.log('File closed');
});
});
6. Fix 4: Use graceful-fs
graceful-fs
is a drop-in replacement for Node’s fs
that retries operations when EMFILE
errors occur.
npm install graceful-fs
Usage:
const fs = require('graceful-fs');
fs.readFile('test.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
7. Fix 5: Increase System File Descriptor Limit
Sometimes, the OS default limit is too low.
Check current limit:
ulimit -n
For permanent changes, update:
- Linux:
/etc/security/limits.conf
- macOS:
launchctl limit maxfiles
Use this carefully—code fixes are better than just increasing limits.
8. Best Practices to Avoid EMFILE
- Use streams instead of loading entire files
- Limit concurrency using queues or
p-limit
- Always close file descriptors
- Use connection pooling for DBs
- Monitor your app with tools like PM2
Conclusion
The “EMFILE: too many open files” error in Node.js is common when handling a large number of files or sockets. By utilizing streams, concurrency limits, proper cleanup, and graceful-fs, you can prevent this error and maintain a stable application.
If needed, raise your system file descriptor limit, but first make sure your code handles resources efficiently.
0 Comments