Production Node.js Stack
Production Node.js with Nginx, PM2, PostgreSQL, Redis, and BullMQ for job queues
Overview
Node.js is a JavaScript runtime built on Chrome's V8 engine that enables server-side JavaScript execution, revolutionizing web development by allowing developers to use a single language across their entire stack. PM2 is a production-grade process manager for Node.js applications that provides clustering, monitoring, and automatic restarts, making it the de facto standard for running Node.js in production environments. This production stack combines Node.js with PM2 for robust application management, NGINX as a high-performance reverse proxy, PostgreSQL for reliable ACID-compliant data storage, and Redis powering both caching and BullMQ job queuing. The architecture creates a scalable, fault-tolerant system where NGINX handles SSL termination and load balancing, PM2 manages Node.js processes in cluster mode, PostgreSQL ensures data integrity, and Redis enables fast session storage and background job processing. This combination is ideal for high-traffic web applications, API services, and enterprise systems that require both performance and reliability. Startups scaling beyond basic deployments, enterprises modernizing legacy systems, and development teams building real-time applications will find this stack provides the production-grade infrastructure needed to handle demanding workloads while maintaining operational simplicity.
Key Features
- PM2 cluster mode with automatic load balancing across CPU cores
- NGINX reverse proxy with SSL/TLS termination and HTTP/2 support
- PostgreSQL ACID compliance with advanced transaction support and JSON/JSONB capabilities
- Redis sub-millisecond caching with rich data structures and pub/sub messaging
- BullMQ job queue processing with Redis-backed persistence and retry mechanisms
- Event-driven Node.js architecture with non-blocking I/O operations
- PM2 automatic restart and crash recovery with zero-downtime deployments
- PostgreSQL full-text search and complex query optimization for analytics
Common Use Cases
- 1E-commerce platforms requiring inventory management, order processing, and payment workflows
- 2SaaS applications with user authentication, subscription billing, and background email processing
- 3Real-time collaboration tools needing WebSocket connections and live data synchronization
- 4Content management systems with image processing, search indexing, and publication workflows
- 5API backends for mobile applications handling user sessions and push notifications
- 6Financial applications requiring transaction integrity and audit trails with background reporting
- 7Social media platforms with user-generated content, real-time feeds, and notification systems
Prerequisites
- Minimum 2GB RAM (PostgreSQL requires 256MB+, Redis 512MB+, Node.js cluster 1GB+)
- Docker and Docker Compose installed with support for multi-service orchestration
- Basic understanding of Node.js ecosystem, npm/yarn, and JavaScript async patterns
- Familiarity with SQL queries and PostgreSQL database administration
- Knowledge of NGINX configuration syntax for reverse proxy and SSL setup
- Understanding of process management concepts and PM2 ecosystem configuration
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 nginx: 3 image: nginx:alpine4 container_name: node-nginx5 restart: unless-stopped6 ports: 7 - "${NGINX_PORT:-80}:80"8 volumes: 9 - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro10 - ./public:/app/public:ro11 depends_on: 12 - app1314 app: 15 build: 16 context: .17 dockerfile: Dockerfile18 container_name: node-app19 restart: unless-stopped20 command: pm2-runtime ecosystem.config.js21 volumes: 22 - ./:/app23 - /app/node_modules24 environment: 25 - NODE_ENV=production26 - PORT=300027 - DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}28 - REDIS_URL=redis://redis:637929 - SESSION_SECRET=${SESSION_SECRET}30 depends_on: 31 - db32 - redis3334 worker: 35 build: 36 context: .37 dockerfile: Dockerfile38 container_name: node-worker39 restart: unless-stopped40 command: node dist/worker.js41 volumes: 42 - ./:/app43 - /app/node_modules44 environment: 45 - NODE_ENV=production46 - DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}47 - REDIS_URL=redis://redis:637948 depends_on: 49 - db50 - redis5152 db: 53 image: postgres:16-alpine54 container_name: node-db55 restart: unless-stopped56 environment: 57 - POSTGRES_USER=${DB_USER}58 - POSTGRES_PASSWORD=${DB_PASSWORD}59 - POSTGRES_DB=${DB_NAME}60 volumes: 61 - postgres_data:/var/lib/postgresql/data6263 redis: 64 image: redis:7-alpine65 container_name: node-redis66 restart: unless-stopped67 volumes: 68 - redis_data:/data6970volumes: 71 postgres_data: 72 redis_data: .env Template
.env
1# Node.js Production Stack2NGINX_PORT=8034# App5SESSION_SECRET=your-session-secret67# Database8DB_USER=node9DB_PASSWORD=node_password10DB_NAME=node_appUsage Notes
- 1Create Dockerfile with Node.js and PM2
- 2Create ecosystem.config.js for PM2 cluster mode
- 3Run migrations with your ORM (Prisma, TypeORM, etc.)
- 4Worker processes BullMQ jobs from Redis
- 5PM2 handles process management and clustering
- 6Scale workers: docker compose up -d --scale worker=3
Individual Services(5 services)
Copy individual services to mix and match with your existing compose files.
nginx
nginx:
image: nginx:alpine
container_name: node-nginx
restart: unless-stopped
ports:
- ${NGINX_PORT:-80}:80
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./public:/app/public:ro
depends_on:
- app
app
app:
build:
context: .
dockerfile: Dockerfile
container_name: node-app
restart: unless-stopped
command: pm2-runtime ecosystem.config.js
volumes:
- ./:/app
- /app/node_modules
environment:
- NODE_ENV=production
- PORT=3000
- DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379
- SESSION_SECRET=${SESSION_SECRET}
depends_on:
- db
- redis
worker
worker:
build:
context: .
dockerfile: Dockerfile
container_name: node-worker
restart: unless-stopped
command: node dist/worker.js
volumes:
- ./:/app
- /app/node_modules
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
db
db:
image: postgres:16-alpine
container_name: node-db
restart: unless-stopped
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME}
volumes:
- postgres_data:/var/lib/postgresql/data
redis
redis:
image: redis:7-alpine
container_name: node-redis
restart: unless-stopped
volumes:
- redis_data:/data
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 nginx:5 image: nginx:alpine6 container_name: node-nginx7 restart: unless-stopped8 ports:9 - "${NGINX_PORT:-80}:80"10 volumes:11 - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro12 - ./public:/app/public:ro13 depends_on:14 - app1516 app:17 build:18 context: .19 dockerfile: Dockerfile20 container_name: node-app21 restart: unless-stopped22 command: pm2-runtime ecosystem.config.js23 volumes:24 - ./:/app25 - /app/node_modules26 environment:27 - NODE_ENV=production28 - PORT=300029 - DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}30 - REDIS_URL=redis://redis:637931 - SESSION_SECRET=${SESSION_SECRET}32 depends_on:33 - db34 - redis3536 worker:37 build:38 context: .39 dockerfile: Dockerfile40 container_name: node-worker41 restart: unless-stopped42 command: node dist/worker.js43 volumes:44 - ./:/app45 - /app/node_modules46 environment:47 - NODE_ENV=production48 - DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}49 - REDIS_URL=redis://redis:637950 depends_on:51 - db52 - redis5354 db:55 image: postgres:16-alpine56 container_name: node-db57 restart: unless-stopped58 environment:59 - POSTGRES_USER=${DB_USER}60 - POSTGRES_PASSWORD=${DB_PASSWORD}61 - POSTGRES_DB=${DB_NAME}62 volumes:63 - postgres_data:/var/lib/postgresql/data6465 redis:66 image: redis:7-alpine67 container_name: node-redis68 restart: unless-stopped69 volumes:70 - redis_data:/data7172volumes:73 postgres_data:74 redis_data:75EOF7677# 2. Create the .env file78cat > .env << 'EOF'79# Node.js Production Stack80NGINX_PORT=808182# App83SESSION_SECRET=your-session-secret8485# Database86DB_USER=node87DB_PASSWORD=node_password88DB_NAME=node_app89EOF9091# 3. Start the services92docker compose up -d9394# 4. View logs95docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/production-nodejs-stack/run | bashTroubleshooting
- PM2 processes not starting: Check ecosystem.config.js syntax and ensure Node.js dependencies are installed with npm ci
- NGINX 502 Bad Gateway: Verify Node.js app is running on port 3000 and container networking allows nginx to reach app service
- PostgreSQL connection refused: Ensure DATABASE_URL format is correct and database container is healthy before app starts
- Redis connection timeout: Check REDIS_URL configuration and verify Redis container is accessible on port 6379
- BullMQ jobs stuck in waiting: Confirm worker container is running and can connect to Redis, check worker.js for error handling
- High memory usage: Monitor PM2 processes with pm2 monit and adjust cluster instances in ecosystem.config.js based on available RAM
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
nginxnodejspm2postgresredis
Tags
#nodejs#express#production#pm2#nginx#postgres#redis#bullmq
Category
Full Web StacksAd Space
Shortcuts: C CopyF FavoriteD Download