Skip to content

Nodejs Deployment

DodaTech 4 min read

title: Node.js Deployment — Complete Guide to Deploying Node.js to Production description: 'Learn Node.js deployment: process managers, environment configuration, CI/CD pipelines, monitoring, logging, load balancing, and cloud platform deployment.' date: 2026-06-28 lastmod: 2026-06-28 weight: 41 tags: [backend, nodejs]


Node.js deployment involves preparing applications for production, configuring process managers, setting up CI/CD, monitoring performance, and deploying to cloud platforms reliably.

## What You'll Learn

By the end of this tutorial, you'll use PM2 for process management, configure environment-specific settings, set up GitHub Actions CI/CD, implement monitoring with logging, and deploy to cloud platforms.

## Why Deployment Matters

Development is half the work. Deploying reliably, monitoring health, and handling failures in production separates professional applications from hobby projects.

## Real-World Use

A production Node.js API runs under PM2 with 4 instances, automatic restart on crash, log rotation, and health checks. GitHub Actions runs tests and deploys to AWS Elastic Beanstalk on every merge.

## Deployment Learning Path

```mermaid
flowchart LR
  A[Docker] --> B[Deployment]
  B --> C[DevOps]
  C --> D[Production]
  D --> E[Next Steps]
  A --> F{You Are Here}
  style F fill:#f90,color:#fff

PM2 Process Manager

npm install -g pm2
// ecosystem.config.js
module.exports = {
  apps: [{
    name: "api-server",
    script: "server.js",
    instances: "max",         // Use all CPU cores
    exec_mode: "cluster",     // Cluster mode for load balancing
    env: { NODE_ENV: "development" },
    env_production: { NODE_ENV: "production" },
    max_memory_restart: "500M",
    log_date_format: "YYYY-MM-DD HH:mm:ss",
    error_file: "./logs/error.log",
    out_file: "./logs/output.log",
    merge_logs: true
  }]
};

Environment Configuration

// config.js
const config = {
  development: {
    port: 3000,
    databaseUrl: "postgresql://localhost:5432/dev",
    logLevel: "debug"
  },
  production: {
    port: parseInt(process.env.PORT, 10) || 8080,
    databaseUrl: process.env.DATABASE_URL,
    logLevel: "info"
  }
};
export default config[process.env.NODE_ENV || "development"];

Health Check Endpoint

app.get("/health", (req, res) => {
  const health = {
    status: "ok",
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    pid: process.pid
  };
  res.json(health);
});

CI/CD with GitHub Actions

name: Deploy
on:
  push:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: "22" }
      - run: npm ci
      - run: npm test
  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: |
          echo "Deploying to production server..."
          # rsync, SSH, or platform CLI

Monitoring and Logging

pm2 monit              # Real-time monitoring
pm2 logs               # View logs
pm2 status             # Process status
pm2 show api-server    # Detailed info

Deployment Platforms

// Platform-specific adjustments
// Heroku: process.env.PORT is provided
// AWS: Use Elastic Beanstalk or ECS
// DigitalOcean: App Platform or Droplets
// Railway/Vercel: Zero-config Node.js hosting

const PORT = process.env.PORT || 3000;
app.listen(PORT, "0.0.0.0", () => {
  console.log(`Server running on port ${PORT}`);
});

Common Mistakes

1. Hardcoding Port or Host

Use process.env.PORT and bind to 0.0.0.0. Cloud platforms assign ports dynamically.

2. No Graceful Shutdown

Not handling SIGTERM causes dropped connections. Listen for shutdown signals and close connections gracefully.

3. Running as Root

Never run Node.js as root. Create a dedicated user or use process managers that drop privileges.

4. No Log Rotation

Without rotation, log files grow indefinitely filling disk space. Configure PM2 log rotation or use external logging.

5. Not Monitoring Application Health

Without health checks and monitoring, you won't know the app is down until users complain.

Practice Questions

1. What is PM2 and why use it?

PM2 is a production process manager that keeps apps alive forever, reloads without downtime, manages logs, and provides monitoring.

2. How do you implement zero-downtime deployment?

Use PM2 in cluster mode with --reload instead of --restart. Reload restarts workers one by one without dropping connections.

3. How do you handle environment-specific configuration?

Use NODE_ENV variable and load the appropriate config file. Never hardcode production credentials in code.

4. What is a graceful shutdown?

Listening for SIGTERM/SIGINT, stopping accepting new requests, finishing in-flight requests, closing DB connections, then exiting.

5. Challenge: Create a deployment-ready Node.js server with health check, graceful shutdown, and PM2 config.

const server = app.listen(PORT, () => console.log(`Running on ${PORT}`));
process.on("SIGTERM", () => {
  console.log("SIGTERM received. Shutting down...");
  server.close(() => process.exit(0));
});

FAQ

Should I use Docker for production deployment?

Yes. Docker ensures consistency between environments. Many cloud platforms (ECS, GKE) require containers.

What is the difference between cluster and fork mode in PM2?

Cluster mode creates multiple instances sharing the port (load balancing). Fork mode runs a single instance.

How do I handle database migrations in deployment?

Run migrations before starting the app. Use npm scripts: npm run migrate && node server.js.

What monitoring tools work with Node.js?

PM2 monitoring, New Relic, Datadog, Sentry (errors), Prometheus + Grafana (metrics), and Winston/Pino (logging).

How do I secure my production Node.js app?

Use Helmet, rate limiting, validate input, run as non-root, keep dependencies updated, use HTTPS, and set proper CORS.

Mini Project: Production-Ready Express Server

Create a deployment-ready Express server with graceful shutdown and health checks.

import express from "express";
const app = express();
app.get("/health", (req, res) => res.json({ status: "ok", uptime: process.uptime() }));
const server = app.listen(process.env.PORT || 3000, "0.0.0.0", () => {
  console.log(`Server running in ${process.env.NODE_ENV} mode`);
});
const shutdown = (signal) => {
  console.log(`${signal} received. Shutting down gracefully...`);
  server.close(() => {
    console.log("HTTP server closed");
    process.exit(0);
  });
  setTimeout(() => process.exit(1), 10000);
};
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));

What's Next

Docker Compose CI/CD Pipeline Express Security

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro