nodejs-app

Deploy a Node.js application - supports PM2, systemd, Docker, or Kubernetes

Recipaie - Deployment Recipe

The template that describes how to deploy this service.

Raw JSON
{
  "$schema": "https://recipaie.com/schemas/recipaie.schema.json",
  "name": "nodejs-app",
  "version": "1.0.0",
  "description": "Deploy a Node.js application - supports PM2, systemd, Docker, or Kubernetes",
  "prerequisites": [
    "Node.js 18+ runtime (unless using containerized deployment)",
    "Application source code or container image",
    "One of: PM2 process manager, systemd, Docker, or Kubernetes"
  ],
  "steps": [
    {
      "order": 1,
      "what": "Assess deployment environment",
      "why": "Node.js apps can run in many ways - choose what fits your infrastructure",
      "when": "Before deployment",
      "how": "Evaluate options: (1) PM2 - simple process manager with clustering and monitoring, (2) systemd - native Linux service management, (3) Docker - containerized isolation, (4) Kubernetes - orchestrated containers. Consider: existing infrastructure, scaling needs, monitoring requirements",
      "verify": "Deployment method chosen based on infrastructure assessment",
      "comments": [
        "PM2 is simplest for single-server deployments",
        "systemd integrates with Linux service management",
        "Docker/K8s best for consistent environments and horizontal scaling"
      ]
    },
    {
      "order": 2,
      "what": "Install Node.js runtime",
      "why": "Required for PM2 and systemd deployments (containers include runtime)",
      "when": "If using PM2 or systemd deployment",
      "skip_if": "Using Docker/K8s (runtime included in image), or Node.js already at required version",
      "how": "Install via package manager: (Ubuntu) curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt install nodejs, (RHEL) dnf module install nodejs:20, (macOS) brew install node@20, (nvm) nvm install 20",
      "verify": "node --version shows v20.x or higher",
      "comments": [
        "Use LTS versions for production (20.x, 22.x)",
        "nvm allows multiple Node versions on same machine",
        "Consider using mise or asdf for polyglot version management"
      ]
    },
    {
      "order": 3,
      "what": "Prepare application",
      "why": "Application needs dependencies and build artifacts",
      "when": "Before running the application",
      "skip_if": "Using pre-built container image with all dependencies",
      "how": "Clone repo or copy source, then: npm ci --production (or npm install --production). If TypeScript or build step required: npm run build",
      "verify": "node_modules exists, build artifacts present if applicable",
      "comments": [
        "npm ci is faster and more reliable than npm install for CI/CD",
        "Use --production to skip devDependencies",
        "For containers: multi-stage build to keep image small"
      ]
    },
    {
      "order": 4,
      "what": "Configure environment variables",
      "why": "12-factor app configuration via environment",
      "when": "Before starting the application",
      "how": "Set required environment variables: NODE_ENV=production, PORT=3000, plus app-specific config. Method depends on deployment: (PM2) ecosystem.config.js env section, (systemd) Environment= in unit file, (Docker) -e flags or env_file, (K8s) ConfigMap/Secret",
      "verify": "Environment variables accessible to application process",
      "comments": [
        "Never commit secrets to source control",
        "Use secret management for sensitive values (Vault, AWS Secrets Manager, K8s Secrets)",
        "Consider .env files for local development only"
      ]
    },
    {
      "order": 5,
      "what": "Deploy and start application",
      "why": "Run the application with your chosen method",
      "when": "After application is prepared",
      "how": "Start using chosen method: (PM2) pm2 start ecosystem.config.js && pm2 save, (systemd) systemctl start myapp && systemctl enable myapp, (Docker) docker run -d --name myapp -p 3000:3000 myapp:latest, (K8s) kubectl apply -f deployment.yaml",
      "verify": "curl http://localhost:3000/health returns success response",
      "comments": [
        "PM2: use pm2 startup to configure boot persistence",
        "systemd: create /etc/systemd/system/myapp.service unit file",
        "Always implement a health check endpoint"
      ]
    },
    {
      "order": 6,
      "what": "Configure process management and monitoring",
      "why": "Ensure application restarts on crash and is monitored",
      "when": "After initial deployment succeeds",
      "skip_if": "Orchestrator handles this (K8s has built-in restart policies)",
      "how": "Configure restart policies: (PM2) automatic with configurable max restarts, (systemd) Restart=always in unit file, (Docker) --restart=unless-stopped. Set up monitoring: PM2 has built-in metrics, or use external APM (Datadog, New Relic, etc.)",
      "verify": "Kill the app process - it should automatically restart within seconds",
      "comments": [
        "PM2: pm2 monit for real-time monitoring",
        "Consider log aggregation (publog, ELK, CloudWatch)",
        "Set up alerting for downtime and error rates"
      ]
    }
  ],
  "step_count": 6
}
Version: 1.0.0
Steps: 6

Prerequisites

Steps

1 Assess deployment environment
Why
Node.js apps can run in many ways - choose what fits your infrastructure
When
Before deployment
How
Evaluate options: (1) PM2 - simple process manager with clustering and monitoring, (2) systemd - native Linux service management, (3) Docker - containerized isolation, (4) Kubernetes - orchestrated containers. Consider: existing infrastructure, scaling needs, monitoring requirements
Verify
Deployment method chosen based on infrastructure assessment
Comments
  • PM2 is simplest for single-server deployments
  • systemd integrates with Linux service management
  • Docker/K8s best for consistent environments and horizontal scaling
2 Install Node.js runtime
Why
Required for PM2 and systemd deployments (containers include runtime)
When
If using PM2 or systemd deployment
Skip If
Using Docker/K8s (runtime included in image), or Node.js already at required version
How
Install via package manager: (Ubuntu) curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt install nodejs, (RHEL) dnf module install nodejs:20, (macOS) brew install node@20, (nvm) nvm install 20
Verify
node --version shows v20.x or higher
Comments
  • Use LTS versions for production (20.x, 22.x)
  • nvm allows multiple Node versions on same machine
  • Consider using mise or asdf for polyglot version management
3 Prepare application
Why
Application needs dependencies and build artifacts
When
Before running the application
Skip If
Using pre-built container image with all dependencies
How
Clone repo or copy source, then: npm ci --production (or npm install --production). If TypeScript or build step required: npm run build
Verify
node_modules exists, build artifacts present if applicable
Comments
  • npm ci is faster and more reliable than npm install for CI/CD
  • Use --production to skip devDependencies
  • For containers: multi-stage build to keep image small
4 Configure environment variables
Why
12-factor app configuration via environment
When
Before starting the application
How
Set required environment variables: NODE_ENV=production, PORT=3000, plus app-specific config. Method depends on deployment: (PM2) ecosystem.config.js env section, (systemd) Environment= in unit file, (Docker) -e flags or env_file, (K8s) ConfigMap/Secret
Verify
Environment variables accessible to application process
Comments
  • Never commit secrets to source control
  • Use secret management for sensitive values (Vault, AWS Secrets Manager, K8s Secrets)
  • Consider .env files for local development only
5 Deploy and start application
Why
Run the application with your chosen method
When
After application is prepared
How
Start using chosen method: (PM2) pm2 start ecosystem.config.js && pm2 save, (systemd) systemctl start myapp && systemctl enable myapp, (Docker) docker run -d --name myapp -p 3000:3000 myapp:latest, (K8s) kubectl apply -f deployment.yaml
Verify
curl http://localhost:3000/health returns success response
Comments
  • PM2: use pm2 startup to configure boot persistence
  • systemd: create /etc/systemd/system/myapp.service unit file
  • Always implement a health check endpoint
6 Configure process management and monitoring
Why
Ensure application restarts on crash and is monitored
When
After initial deployment succeeds
Skip If
Orchestrator handles this (K8s has built-in restart policies)
How
Configure restart policies: (PM2) automatic with configurable max restarts, (systemd) Restart=always in unit file, (Docker) --restart=unless-stopped. Set up monitoring: PM2 has built-in metrics, or use external APM (Datadog, New Relic, etc.)
Verify
Kill the app process - it should automatically restart within seconds
Comments
  • PM2: pm2 monit for real-time monitoring
  • Consider log aggregation (publog, ELK, CloudWatch)
  • Set up alerting for downtime and error rates

Prodaie - Execution Record

What happened when an AI executed this recipe in different environments.

Raw JSON
{
  "$schema": "https://recipaie.com/schemas/prodaie.schema.json",
  "name": "nodejs-app",
  "description": "Deployment record showing Node.js app deployed via different methods: PM2, Docker, and Kubernetes",
  "prerequisites": [
    "Node.js 18+ runtime (unless using containerized deployment)",
    "Application source code or container image",
    "One of: PM2 process manager, systemd, Docker, or Kubernetes"
  ],
  "locations": [
    {
      "path": "dev-server (PM2)",
      "description": "Single development server using PM2 for process management",
      "status": "complete",
      "step_count": 6,
      "steps": [
        {
          "order": 1,
          "what": "Assess deployment environment",
          "why": "Node.js apps can run in many ways - choose what fits your infrastructure",
          "when": "Before deployment",
          "how": "Evaluate options: PM2, systemd, Docker, or Kubernetes",
          "verify": "Deployment method chosen based on infrastructure assessment",
          "success": true,
          "details": "chose PM2 for simplicity, already familiar with ecosystem.config.js"
        },
        {
          "order": 2,
          "what": "Install Node.js runtime",
          "why": "Required for PM2 and systemd deployments",
          "when": "If using PM2 or systemd deployment",
          "skip_if": "Using Docker/K8s or Node.js already at required version",
          "how": "Install via package manager or nvm",
          "verify": "node --version shows v20.x or higher",
          "success": true,
          "details": "nvm install 20 && nvm use 20, shows v20.10.0"
        },
        {
          "order": 3,
          "what": "Prepare application",
          "why": "Application needs dependencies and build artifacts",
          "when": "Before running the application",
          "skip_if": "Using pre-built container image",
          "how": "npm ci --production, then npm run build if needed",
          "verify": "node_modules exists, build artifacts present",
          "success": true,
          "details": "npm ci --production && npm run build, dist/ folder created"
        },
        {
          "order": 4,
          "what": "Configure environment variables",
          "why": "12-factor app configuration via environment",
          "when": "Before starting the application",
          "how": "Set NODE_ENV=production, PORT, and app-specific config in ecosystem.config.js",
          "verify": "Environment variables accessible to application process",
          "success": true,
          "details": "added env section to ecosystem.config.js with NODE_ENV=production, PORT=3000"
        },
        {
          "order": 5,
          "what": "Deploy and start application",
          "why": "Run the application with your chosen method",
          "when": "After application is prepared",
          "how": "pm2 start ecosystem.config.js && pm2 save",
          "verify": "curl http://localhost:3000/health returns success",
          "success": true,
          "details": "pm2 start ecosystem.config.js, /health returns {\"status\":\"ok\"}"
        },
        {
          "order": 6,
          "what": "Configure process management and monitoring",
          "why": "Ensure application restarts on crash and is monitored",
          "when": "After initial deployment succeeds",
          "skip_if": "Orchestrator handles this",
          "how": "Configure restart policies and monitoring",
          "verify": "Kill the app process - it should restart automatically",
          "success": true,
          "details": "pm2 startup configured, tested kill -9 and app restarted in 2s"
        }
      ]
    },
    {
      "path": "staging-cluster (Docker)",
      "description": "Docker deployment on staging cluster",
      "status": "complete",
      "step_count": 6,
      "steps": [
        {
          "order": 1,
          "what": "Assess deployment environment",
          "why": "Node.js apps can run in many ways",
          "when": "Before deployment",
          "how": "Evaluate options based on infrastructure",
          "verify": "Deployment method chosen",
          "success": true,
          "details": "chose Docker for consistent environment with production"
        },
        {
          "order": 2,
          "what": "Install Node.js runtime",
          "why": "Required for PM2 and systemd deployments",
          "when": "If using PM2 or systemd deployment",
          "skip_if": "Using Docker/K8s",
          "how": "Install via package manager",
          "verify": "node --version shows v20.x",
          "success": true,
          "details": "using Docker, Node.js included in container image"
        },
        {
          "order": 3,
          "what": "Prepare application",
          "why": "Application needs dependencies and build artifacts",
          "when": "Before running the application",
          "skip_if": "Using pre-built container image",
          "how": "npm ci --production, npm run build",
          "verify": "Build artifacts present",
          "success": true,
          "details": "multi-stage Dockerfile builds image with npm ci && npm run build, final image 145MB"
        },
        {
          "order": 4,
          "what": "Configure environment variables",
          "why": "12-factor app configuration",
          "when": "Before starting the application",
          "how": "Set environment variables via docker run -e or env_file",
          "verify": "Environment variables accessible",
          "success": true,
          "details": "created .env.staging with all config, using --env-file in docker run"
        },
        {
          "order": 5,
          "what": "Deploy and start application",
          "why": "Run the application",
          "when": "After application is prepared",
          "how": "docker run -d --name myapp -p 3000:3000 myapp:latest",
          "verify": "curl http://localhost:3000/health returns success",
          "success": true,
          "details": "docker run -d --name api-staging -p 3000:3000 --env-file .env.staging myapp:v1.2.3"
        },
        {
          "order": 6,
          "what": "Configure process management and monitoring",
          "why": "Ensure application restarts on crash",
          "when": "After initial deployment succeeds",
          "skip_if": "Orchestrator handles this",
          "how": "Use --restart=unless-stopped",
          "verify": "Kill the app process - it should restart",
          "success": true,
          "details": "using --restart=unless-stopped, verified restart after docker stop/start"
        }
      ]
    },
    {
      "path": "prod-cluster (Kubernetes)",
      "description": "Production Kubernetes cluster with HPA",
      "status": "complete",
      "step_count": 6,
      "steps": [
        {
          "order": 1,
          "what": "Assess deployment environment",
          "why": "Node.js apps can run in many ways",
          "when": "Before deployment",
          "how": "Evaluate options based on infrastructure",
          "verify": "Deployment method chosen",
          "success": true,
          "details": "chose Kubernetes for auto-scaling and zero-downtime deployments"
        },
        {
          "order": 2,
          "what": "Install Node.js runtime",
          "why": "Required for PM2 and systemd deployments",
          "when": "If using PM2 or systemd deployment",
          "skip_if": "Using Docker/K8s",
          "how": "Install via package manager",
          "verify": "node --version shows v20.x",
          "success": true,
          "details": "using Kubernetes, runtime in container image"
        },
        {
          "order": 3,
          "what": "Prepare application",
          "why": "Application needs dependencies and build artifacts",
          "when": "Before running the application",
          "skip_if": "Using pre-built container image",
          "how": "Build and push container image to registry",
          "verify": "Image in registry",
          "success": true,
          "details": "CI/CD builds image, pushed to registry.company.com/api:v1.2.3"
        },
        {
          "order": 4,
          "what": "Configure environment variables",
          "why": "12-factor app configuration",
          "when": "Before starting the application",
          "how": "Create ConfigMap and Secret in Kubernetes",
          "verify": "ConfigMap and Secret exist in namespace",
          "success": true,
          "details": "created api-config ConfigMap and api-secrets Secret in prod namespace"
        },
        {
          "order": 5,
          "what": "Deploy and start application",
          "why": "Run the application",
          "when": "After application is prepared",
          "how": "kubectl apply -f deployment.yaml",
          "verify": "curl http://api-service/health returns success",
          "success": true,
          "details": "deployed 3 replicas, rolling update completed, /health returning 200"
        },
        {
          "order": 6,
          "what": "Configure process management and monitoring",
          "why": "Ensure application restarts on crash",
          "when": "After initial deployment succeeds",
          "skip_if": "Orchestrator handles this",
          "how": "K8s has built-in restart policies",
          "verify": "Kill a pod - it should be recreated",
          "success": true,
          "details": "liveness/readiness probes configured, HPA scales 3-10 replicas based on CPU"
        }
      ]
    }
  ]
}
Locations: 3

Locations

dev-server (PM2) complete

Single development server using PM2 for process management

Steps: 6
1 Assess deployment environment
Why
Node.js apps can run in many ways - choose what fits your infrastructure
When
Before deployment
How
Evaluate options: PM2, systemd, Docker, or Kubernetes
Verify
Deployment method chosen based on infrastructure assessment
Result
chose PM2 for simplicity, already familiar with ecosystem.config.js
2 Install Node.js runtime
Why
Required for PM2 and systemd deployments
When
If using PM2 or systemd deployment
Skip If
Using Docker/K8s or Node.js already at required version
How
Install via package manager or nvm
Verify
node --version shows v20.x or higher
Result
nvm install 20 && nvm use 20, shows v20.10.0
3 Prepare application
Why
Application needs dependencies and build artifacts
When
Before running the application
Skip If
Using pre-built container image
How
npm ci --production, then npm run build if needed
Verify
node_modules exists, build artifacts present
Result
npm ci --production && npm run build, dist/ folder created
4 Configure environment variables
Why
12-factor app configuration via environment
When
Before starting the application
How
Set NODE_ENV=production, PORT, and app-specific config in ecosystem.config.js
Verify
Environment variables accessible to application process
Result
added env section to ecosystem.config.js with NODE_ENV=production, PORT=3000
5 Deploy and start application
Why
Run the application with your chosen method
When
After application is prepared
How
pm2 start ecosystem.config.js && pm2 save
Verify
curl http://localhost:3000/health returns success
Result
pm2 start ecosystem.config.js, /health returns {"status":"ok"}
6 Configure process management and monitoring
Why
Ensure application restarts on crash and is monitored
When
After initial deployment succeeds
Skip If
Orchestrator handles this
How
Configure restart policies and monitoring
Verify
Kill the app process - it should restart automatically
Result
pm2 startup configured, tested kill -9 and app restarted in 2s
staging-cluster (Docker) complete

Docker deployment on staging cluster

Steps: 6
1 Assess deployment environment
Why
Node.js apps can run in many ways
When
Before deployment
How
Evaluate options based on infrastructure
Verify
Deployment method chosen
Result
chose Docker for consistent environment with production
2 Install Node.js runtime
Why
Required for PM2 and systemd deployments
When
If using PM2 or systemd deployment
Skip If
Using Docker/K8s
How
Install via package manager
Verify
node --version shows v20.x
Result
using Docker, Node.js included in container image
3 Prepare application
Why
Application needs dependencies and build artifacts
When
Before running the application
Skip If
Using pre-built container image
How
npm ci --production, npm run build
Verify
Build artifacts present
Result
multi-stage Dockerfile builds image with npm ci && npm run build, final image 145MB
4 Configure environment variables
Why
12-factor app configuration
When
Before starting the application
How
Set environment variables via docker run -e or env_file
Verify
Environment variables accessible
Result
created .env.staging with all config, using --env-file in docker run
5 Deploy and start application
Why
Run the application
When
After application is prepared
How
docker run -d --name myapp -p 3000:3000 myapp:latest
Verify
curl http://localhost:3000/health returns success
Result
docker run -d --name api-staging -p 3000:3000 --env-file .env.staging myapp:v1.2.3
6 Configure process management and monitoring
Why
Ensure application restarts on crash
When
After initial deployment succeeds
Skip If
Orchestrator handles this
How
Use --restart=unless-stopped
Verify
Kill the app process - it should restart
Result
using --restart=unless-stopped, verified restart after docker stop/start
prod-cluster (Kubernetes) complete

Production Kubernetes cluster with HPA

Steps: 6
1 Assess deployment environment
Why
Node.js apps can run in many ways
When
Before deployment
How
Evaluate options based on infrastructure
Verify
Deployment method chosen
Result
chose Kubernetes for auto-scaling and zero-downtime deployments
2 Install Node.js runtime
Why
Required for PM2 and systemd deployments
When
If using PM2 or systemd deployment
Skip If
Using Docker/K8s
How
Install via package manager
Verify
node --version shows v20.x
Result
using Kubernetes, runtime in container image
3 Prepare application
Why
Application needs dependencies and build artifacts
When
Before running the application
Skip If
Using pre-built container image
How
Build and push container image to registry
Verify
Image in registry
Result
CI/CD builds image, pushed to registry.company.com/api:v1.2.3
4 Configure environment variables
Why
12-factor app configuration
When
Before starting the application
How
Create ConfigMap and Secret in Kubernetes
Verify
ConfigMap and Secret exist in namespace
Result
created api-config ConfigMap and api-secrets Secret in prod namespace
5 Deploy and start application
Why
Run the application
When
After application is prepared
How
kubectl apply -f deployment.yaml
Verify
curl http://api-service/health returns success
Result
deployed 3 replicas, rolling update completed, /health returning 200
6 Configure process management and monitoring
Why
Ensure application restarts on crash
When
After initial deployment succeeds
Skip If
Orchestrator handles this
How
K8s has built-in restart policies
Verify
Kill a pod - it should be recreated
Result
liveness/readiness probes configured, HPA scales 3-10 replicas based on CPU