Cómo solucionar EADDRINUSE en Node.js
Error: listen EADDRINUSE significa que el puerto ya está ocupado. Cómo encontrar el proceso en Mac, terminarlo, cambiar tu puerto y evitar que el error vuelva.
Ejecutas node server.js y Node lanza:
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (node:net:...)
Significa exactamente lo que dice: otro proceso ya está escuchando en el puerto que tu app quiere. Aquí tienes la solución rápida y cómo evitar que se repita.
Qué significa EADDRINUSE
Cuando tu servidor Node llama a app.listen(3000), le pide al sistema operativo vincularse al puerto 3000. Si algo ya ocupa ese puerto, el bind falla y Node expone el error del sistema EADDRINUSE (“address already in use”). El :::3000 del mensaje es la forma IPv6 de “puerto 3000 en todas las interfaces”.
Nueve de cada diez veces en desarrollo, el culpable es una instancia anterior de tu propio servidor que no se cerró: un proceso caído, un nodemon atascado o una terminal que cerraste sin detener el servidor.
Paso 1: Encuentra qué ocupa el puerto
En un Mac:
lsof -i :3000 -n -P
COMMAND PID USER ... NODE NAME
node 1421 aaron ... TCP *:3000 (LISTEN)
Ahí está: un proceso node huérfano, PID 1421, todavía sentado en el 3000.
Paso 2: Termínalo
El comando de una línea que encuentra y termina lo que sea que ocupe el puerto:
kill -9 $(lsof -ti :3000)
lsof -ti :3000 imprime solo el PID; kill -9 lo termina por la fuerza. Ahora el puerto 3000 está libre y node server.js arrancará.
Para un cierre más limpio que permita al proceso liberar recursos primero, prueba un kill simple (SIGTERM) antes de recurrir a -9 (SIGKILL):
kill $(lsof -ti :3000)
Más sobre la elección entre SIGTERM y SIGKILL en matar un proceso por puerto en Mac.
Paso 3 (alternativa): Ejecuta en otro puerto
Si no quieres rastrear el otro proceso, simplemente mueve tu app:
PORT=3001 node server.js
Esto funciona cuando tu código lee el puerto del entorno, como debería hacer:
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Escuchando en ${port}`));
Evita que EADDRINUSE vuelva
Unos cuantos hábitos eliminan la mayoría de los reincidentes:
Maneja el error en lugar de caer a ciegas. Captúralo e imprime algo útil:
const server = app.listen(port);
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
console.error(`El puerto ${port} ya está en uso. Detén el otro proceso o define otro PORT.`);
process.exit(1);
} else {
throw err;
}
});
Cierra de forma limpia con Ctrl-C para que el puerto se libere cuando detienes el servidor:
process.on('SIGINT', () => {
server.close(() => process.exit(0));
});
Usa un gestor de procesos como nodemon o pm2, que reinicia tu app y libera el puerto antiguo entre ejecuciones en lugar de dejar huérfanos.
Por qué pasa en realidad
El error es solo Node informando de la regla universal de que solo un programa puede escuchar en un puerto a la vez. EADDRINUSE es la cara en Node.js de la misma condición de fondo que está detrás del bind: address already in use de la shell: misma causa, mismas soluciones.
Ve el proceso huérfano al instante
Portie muestra cada proceso que ocupa un puerto en tu Mac en una tabla en vivo. Cuando Node lanza EADDRINUSE, ves el servidor sobrante sentado en el puerto 3000 y lo terminas con un clic, sin necesidad de conjuros con lsof.
El monitoreo local es gratuito. El desbloqueo de $8.99 (pago único) agrega la terminación de procesos con un clic y el escaneo remoto de puertos. Descarga Portie y termina los servidores huérfanos en cuanto aparecen.