Deploy next.js using pm2 cluster mode(and with docker)

2024-09-03

We can simply start the Next.js application using next start. However, when facing higher traffic demands in practical use, how can we deploy Next.js using a multi-process approach?

We can achieve this using the cluster mode of pm2. The cluster mode is a powerful way of scaling Node.js applications, allowing you to start multiple processes, all listening on the same port. How do we do this? First, we can create a .json file to describe the pm2 task (named pm2.json):

{
  "apps": [
    {
      "name": "next",
      "script": "next",
      "args": "start --port 3000",
      "exec_mode": "cluster_mode",
      "instances": 2,
      "log_file": "server.log",
      "merge_logs": true
    }
  ]
}

Let me explain the configuration here:

  • exec_mode is the execution mode, which needs to be set to “cluster_mode” (writing “cluster” also works).
  • instances is the number of processes to start. If you write “max”, it will start processes based on the number of CPU cores.
  • merge_logs is to have different processes write to the same log file. Otherwise, it will separate log files.

After writing the configuration file and building, you can use pm2 to start the Next.js application by:

pm2 start pm2.json

After starting, you should see the output of each process starting. You can then ps aux | grep next to see multiple Next.js processes running.

Now, let me explain how to start a Next.js application using pm2 in Docker. In Docker, we need to use pm2-runtime instead of pm2 to start the application. This is because pm2 will daemonize the target process, causing the Docker container to exit.

However, directly using pm2-runtime will cause an issue, as there is no resident pm2 process, so pm2-runtime will look for the built files in the wrong path, such as pm2.json/. Therefore, we need to start the pm2 process first, and then use pm2-runtime to execute. The method is as follows:

sudo docker run -it --entrypoint "/bin/bash" \
                -v $(pwd):/workdir --workdir /workdir \
                -p 3000:3000 \
                node:latest \
                -c "npx pm2 list && npx pm2-runtime start pm2.json"

This how we can start a multi-process next.js app inside a docker container.