Next.js API processes hit 'Too many open files' under load behind PM2 — 500s only in production
Environment
Next.js 13 app deployed on Ubuntu 22.04 VMs managed by PM2 cluster mode (4 worker processes). Production uses proxy (NGINX) and networked log aggregation. Load test and production peaks observed — error rate rises only in prod under sustained traffic bursts.
Symptoms
Under high concurrency, API routes intermittently return HTTP 500 and PM2 worker logs show 'Error: EMFILE: too many open files' stack traces referencing fs.readFileSync and a custom temp-file cleanup routine. Local development and staging (lower concurrency) do not show the issue.
Observations
ulimit -n on host is 1024. PM2 spawns 4 workers; each worker appears to open many file descriptors (sockets to upstream auth service, DB connections, file handles). lsof during peak shows many file descriptors in TIME_WAIT and open file handles to /tmp/app-*.tmp. The app uses synchronous file writes/reads for multipart processing and relies on process.on('exit') for cleanup. Application code occasionally leaves temp files if process crashes.
Already attempted
Increased ulimit for one test VM to 65536 and restarted PM2 — error frequency dropped but not eliminated. Replaced synchronous fs.readFileSync with async streaming in a few critical handlers in a canary build — those endpoints improved. Rotated temp file cleanup to periodic cron but didn't deploy cluster-wide yet. No evidence of FD leak in native modules.
Question
What's the best approach to identify and fix the cause of EMFILE in production Next.js behind PM2, and what immediate production mitigations are safe to apply without code rollbacks?
Verified community troubleshooting
No answers yet..