Sling Academy
Home/Node.js/Should you use Docker or PM2 to run Node.js apps in production

Should you use Docker or PM2 to run Node.js apps in production

Last updated: December 29, 2023

Introduction

When it comes to running Node.js applications in production, there are multiple options each with their own strengths and considerations. Docker and PM2 are two popular choices for deploying Node.js apps. This tutorial explores what each tool offers, with practical examples and comparisons to aid in determining which might suit your production needs better.

What is Docker?

Docker is a containerization platform that enables developers to package applications into containers—standardized executable components combining app source code with the operating system (OS) libraries and dependencies required to run that code in any environment.

Working with Docker

Basic Example: packaging a Node.js application into a Docker container.

FROM node:14
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "node", "app.js" ]

This Dockerfile does the following:

  • Sets the base image as ‘node:14’
  • Creates a working directory in the container
  • Copies package files and installs dependencies
  • Copies the rest of the app’s source code
  • Exposes port 8080 to the host system
  • Defines the command to run the app using Node.js

What is PM2?

PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, reload them without downtime, and facilitate common DevOps tasks.

Working with PM2

Basic Example: starting a Node.js application with PM2.

pm2 start app.js

Comparing Capacity and Portability

Docker containers encapsulate the whole runtime environment, making them portable across different systems. In contrast, PM2 is an application-level process manager which requires the system environment to be prepared separately.

Advanced Use-Case Examples

PM2: Using cluster mode to scale an application across multiple CPU cores.

pm2 start app.js -i max

This command allows the Node.js app to balance load across all CPU cores available.

Docker: Scaling a containerized app across hosts with Docker Swarm or Kubernetes.

docker service create --replicas 3 -p 80:8080 --name my-app my-node-app

This example creates multiple microservices and balances the load across them.

Docker and PM2 in Harmony

You can use both Docker and PM2 in tandem. Here’s a complex compose file using Docker and letting PM2 manage the Node.js app within the container.

version: '3'
services:
  nodejs-app:
    build: .
    ports:
      - "80:8080"
    command: pm2-runtime start ecosystem.config.js

The ‘command’ overrides the default Docker CMD with PM2, effectively utilizing PM2’s features inside the container.

Operational Considerations

Docker ensures consistency across environments but requires container management infrastructure. PM2 offers a simpler operational approach but lacks the complete isolation and control that comes with containerization.

Resource Efficiency

Containers often increase overhead due to the inclusion of a full OS in the image. In comparison, PM2 manages the Node.js process directly allowing for potentially better resource usage.

Monitoring and Management

Docker and PM2 also differ in how they monitor and manage applications. Docker focuses on container health, while PM2 provides more detailed application-specific metrics.

Complex Example for Node.js App Using Docker and PM2

FROM node:14
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
COPY ecosystem.config.js .
CMD [ "pm2-runtime", "start", "ecosystem.config.js" ]

The build process copies an ecosystem configuration file into the image and PM2-runtime as the main process manager instead of directly invoking ‘node’.

Conclusion

Choosing between Docker and PM2 is not straightforward. Docker excels in creating consistent environments and scaling across hosts. PM2’s strength lies in simplifying deployments through process management and enabling practical operational solutions. Your choice will depend on several factors, including your team’s expertise, your existing infrastructure, the complexity of your application, and specific use cases.

In practice, many choose to employ both by running a PM2 process manager inside Docker containers to combine the benefits of both methods. Consider the requirements of your Node.js application and the nature of your production environment to make the best choice between Docker, PM2, or leveraging the strengths of both tools in unison.

Next Article: How to Send Email in Node.js (3 Approaches)

Previous Article: How to Write C/C++ Addons for Node.js

Series: Node.js Intermediate Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates