Cuando desarrollas una aplicacion Node.js, ejecutarla con node index.js funciona perfectamente en tu maquina local. Pero en produccion, esa aproximacion tiene problemas serios: si la aplicacion crashea, nadie la reinicia; si el servidor se reinicia, tu app no levanta sola; y si tienes un servidor con multiples nucleos, solo estas usando uno. PM2 resuelve todos estos problemas y mas.
PM2 es un gestor de procesos para aplicaciones Node.js disenado especificamente para entornos de produccion. Sus capacidades principales incluyen:
Instala PM2 de forma global en tu servidor:
npm install -g pm2
La forma mas basica de iniciar una aplicacion es:
pm2 start app.js
Esto inicia el proceso, le asigna un ID y un nombre (por defecto el nombre del archivo). Puedes verificar el estado con:
pm2 status
Veras una tabla con el ID, nombre, modo, PID, estado, uso de CPU y memoria de cada proceso. Otros comandos basicos que usaras constantemente:
pm2 stop app # Detener por nombre
pm2 restart app # Reiniciar
pm2 delete app # Eliminar del registro de PM2
pm2 logs app # Ver logs en tiempo real
pm2 logs app --lines 200 # Ver ultimas 200 lineas
Ejecutar pm2 start app.js esta bien para pruebas rapidas, pero en produccion necesitas un archivo de configuracion que defina exactamente como debe ejecutarse tu aplicacion. Este archivo es ecosystem.config.js:
module.exports = {
apps: [
{
name: "mi-api",
script: "./src/index.js",
instances: "max",
exec_mode: "cluster",
env: {
NODE_ENV: "production",
PORT: 3000
},
env_staging: {
NODE_ENV: "staging",
PORT: 3001
},
max_memory_restart: "500M",
log_date_format: "YYYY-MM-DD HH:mm:ss Z",
error_file: "./logs/error.log",
out_file: "./logs/output.log",
merge_logs: true,
autorestart: true,
max_restarts: 10,
min_uptime: "10s",
restart_delay: 4000,
watch: false,
ignore_watch: ["node_modules", "logs"],
}
]
};
Para iniciar con este archivo:
pm2 start ecosystem.config.js
Para usar las variables de un entorno especifico:
pm2 start ecosystem.config.js --env staging
Desglosemos las opciones mas relevantes del ecosystem file.
Estas dos opciones trabajan juntas. Cuando defines exec_mode: "cluster" e instances: "max", PM2 crea una instancia de tu aplicacion por cada nucleo del CPU disponible. En un servidor con 4 nucleos, tendras 4 procesos sirviendo peticiones en paralelo.
Puedes usar un numero fijo (instances: 2) o un porcentaje (instances: "50%") si no quieres saturar el servidor. El modo cluster usa el modulo cluster nativo de Node.js, asi que funciona de forma transparente con servidores HTTP.
Esta opcion es critica para prevenir memory leaks. Si un proceso supera el umbral definido (por ejemplo, "500M"), PM2 lo reinicia automaticamente. Esto no es una solucion al leak, pero evita que tu servidor se quede sin memoria mientras investigas el problema.
Estas opciones previenen loops de reinicio infinitos. Si tu aplicacion crashea antes de cumplir min_uptime (por ejemplo, 10 segundos), PM2 la cuenta como un reinicio fallido. Despues de alcanzar max_restarts reinicios fallidos, PM2 detiene la aplicacion en lugar de seguir intentando. Esto te protege de una aplicacion que tiene un error fatal en el arranque y consumiria recursos reiniciandose indefinidamente.
Agrega un delay entre reinicios. Util cuando tu aplicacion depende de un servicio externo que podria estar temporalmente caido. Un delay de 4000ms evita bombardear ese servicio con intentos de conexion rapidos.
Los logs son fundamentales para diagnosticar problemas en produccion. PM2 centraliza los logs de todas tus aplicaciones. Los comandos principales son:
pm2 logs # Todos los logs en tiempo real
pm2 logs mi-api # Solo logs de una app
pm2 logs --lines 500 # Ultimas 500 lineas
pm2 flush # Limpiar todos los logs
El problema es que los archivos de log crecen indefinidamente. Para esto existe pm2-logrotate:
pm2 install pm2-logrotate
Configuralo segun tus necesidades:
pm2 set pm2-logrotate:max_size 50M # Rotar cuando llegue a 50MB
pm2 set pm2-logrotate:retain 10 # Mantener 10 archivos rotados
pm2 set pm2-logrotate:compress true # Comprimir logs rotados
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD_HH-mm-ss
pm2 set pm2-logrotate:rotateInterval '0 0 * * *' # Rotar diariamente
De nada sirve tener PM2 si al reiniciar el servidor tus aplicaciones no levantan. Para esto, PM2 genera un script de startup para tu sistema operativo:
pm2 startup
Este comando imprimira una linea que debes ejecutar con permisos de root. Por ejemplo, en un servidor Ubuntu:
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u deploy --hp /home/deploy
Despues de configurar todas tus aplicaciones, guarda el estado actual:
pm2 save
Ahora, cuando el servidor reinicie, PM2 arrancara automaticamente y restaurara todas las aplicaciones que tenia corriendo.
Esta es una de las funcionalidades mas valiosas de PM2. Cuando necesitas actualizar tu aplicacion, un pm2 restart mata todos los procesos y los vuelve a crear, lo que genera unos segundos de downtime. En cambio, pm2 reload actualiza los procesos uno por uno en modo cluster:
pm2 reload mi-api
PM2 inicia una nueva instancia, espera a que este lista, redirige el trafico a ella y recien entonces mata la instancia anterior. Repite este proceso con cada instancia del cluster. El resultado es que siempre hay al menos una instancia atendiendo peticiones.
Para que esto funcione correctamente, tu aplicacion debe manejar la senal SIGINT para cerrar conexiones de forma ordenada:
process.on('SIGINT', () => {
// Cerrar conexiones a base de datos
// Terminar requests en progreso
server.close(() => {
process.exit(0);
});
});
Tambien puedes configurar el tiempo maximo de espera antes de forzar el kill:
// En ecosystem.config.js
kill_timeout: 5000, // 5 segundos para cerrar limpiamente
listen_timeout: 8000 // 8 segundos para considerar la app lista
Un flujo de despliegue comun con PM2 se ve asi:
#!/bin/bash
# deploy.sh
cd /var/www/mi-api
# Traer ultimos cambios
git pull origin main
# Instalar dependencias (solo produccion)
npm ci --production
# Ejecutar migraciones si las hay
npm run migrate
# Reload sin downtime
pm2 reload ecosystem.config.js --env production
# Verificar que todo esta corriendo
pm2 status
Si usas CI/CD (GitHub Actions, GitLab CI, etc.), este script se ejecuta automaticamente despues de cada push a la rama principal.
PM2 incluye un monitor basico en la terminal:
pm2 monit
Esto muestra un dashboard interactivo con metricas de CPU, memoria, loop delay y logs de cada proceso. Para monitoreo mas avanzado, PM2 ofrece PM2 Plus (antes Keymetrics), una plataforma web que incluye alertas, metricas historicas y debugging remoto.
Tambien puedes consultar metricas por API para integrarlo con tus propias herramientas de monitoreo:
pm2 prettylist # Informacion detallada en formato JSON legible
pm2 show mi-api # Detalle de un proceso especifico
Algunas recomendaciones finales para un setup robusto en produccion:
/health) que verifique conexiones a base de datos y servicios externos. Esto facilita la integracion con balanceadores de carga.app.get('/health', async (req, res) => {
try {
await db.query('SELECT 1');
res.status(200).json({ status: 'ok', uptime: process.uptime() });
} catch (error) {
res.status(503).json({ status: 'error', message: 'Database unavailable' });
}
});
PM2 es una herramienta madura y estable que resuelve la mayoria de problemas operacionales de Node.js en produccion. Configurado correctamente, puede mantener tus aplicaciones corriendo de forma confiable durante meses sin intervencion manual.