DEV Community


How to CI/CD using PM2 for your Node.js project

t410 profile image Tayyib Cankat ・6 min read


You have a Node.js project in your local machine but you don't know how to deploy it to your remote server or you use old fashioned way by copying the contents from your computer to the remote server using FTP?

Well, you can automate this process and make your life easier using PM2 *insert hooray gif here*


PM2 is a Process Manager for Node.js. It's like Task Manager in Windows and Activity Monitor in macOS.

You can -including but not limited to- manage your application, scale, start and stop. But the most important feature we want is deploying.

In this post, we will learn how to deploy our application to our remote server and run/build it with a single console command.


Step 1: Create a Project

First, we obviously need a project.
We create a folder and cd into it.

mkdir pm2-deploy; cd pm2-deploy
Enter fullscreen mode Exit fullscreen mode

Then we initialize the folder as a node project.

npm init -y
Enter fullscreen mode Exit fullscreen mode

We can then go ahead and install express to serve static files in node environment.

npm i express
Enter fullscreen mode Exit fullscreen mode

And we need to create a JS file to write our code that will serve the folder public which we also need to create.

I have created index.js in the root directory. You can rename it whatever you want but don't forget that you need to change the main field in the package.json file also.

We also need an HTML file to be served in that public folder.

Your file structure now looks like this:
File structure

Here's my index.js

express is serving a static folder named public and its contents in port 3000; Nothing fancy here.

In index.html we do nothing special.

Now we can use

npm start
Enter fullscreen mode Exit fullscreen mode

We should see the console.log output which is PM2 Project is now live @ localhost:3000.

We can check if that's working by going to that port. Go to localhost:3000 in the browser, If you see YAY! that's great.

Step 2: Install PM2 globally

We need to install PM2 npm package globally. We can install it by using

npm i -g pm2
Enter fullscreen mode Exit fullscreen mode

Now onto Step 3!

Step 3: Initialize git

We cannot have a CI/CD without a version control system, right? So we need to push our project to a git service. I will use Github for that.

When you create a git repo you will see the necessary instructions on how to push an existing project.
But here are the necessary commands, just in case:

git init
git remote add origin<your_github_username>/<your_repository_name>.git
git add .
git commit -m "Initial Commit"
git branch -M main
git push -u origin main
Enter fullscreen mode Exit fullscreen mode

Note: I strongly recommend using SSH Connection instead of using HTTPS for Github. Your life will get better and securerer :)

Step 4: Configuring the remote machine

In this step, I won't go into the details of how to create/reserve a virtual remote machine but keep in mind that I am using Ubuntu on an EC2 (AWS) machine.

First, we need to connect to the remote machine using SSH
ssh -i path_to_key_file remote_username@remote_ip

I assume you have already done nvm, npm installations, if not you can go ahead and check the nvm repo here:

One important thing to do here. We need to move the lines that were added by nvm to our .bashrc file to the top. Your system may be using .bash_profile or something else. Just pay attention to the output of the nvm installation.

These are the lines we need to move. Open your favorite editor and move them to the top of the file.

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/" ] && \. "$NVM_DIR/"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
Enter fullscreen mode Exit fullscreen mode

After saving and exiting the file we can install PM2 here too as we did in Step 2.

npm i -g pm2

After the installation

pm2 startup

will give you a simple instruction on how to make PM2 start automatically every time your remote system reboots. I strongly recommend doing that.

Now that we installed PM2, we need to create an SSH key and add it to Github.

In the remote machine, you can go ahead and type

ssh-keygen -t ed25519 -C "<your_github_email>"
Enter fullscreen mode Exit fullscreen mode

Further reading on how to create ssh key

The keygen will ask you the name of the key. If you want to change it (I strongly advise you not to do that) you need to give the full path here.

You may just hit Enter when asking for password.

After creating the key we need to copy the contents of the public key.

cat /home/ubuntu/.ssh/
Enter fullscreen mode Exit fullscreen mode

Go ahead and copy the text you see starting with ssh- and ending with your e-mail (included).

Then go to while logged in to Github then click New SSH Key button. You can give a title and paste the copied text into the key field.

We now have given authorization to our remote machine to connect to our Github. But we need to connect to Github just once to mark the connection trusted in our remote machine. To do that we can clone the repository into the remote machine.

git clone
Enter fullscreen mode Exit fullscreen mode

Of course, it will be your username and your repo name.
The console will ask you if you want to continue connecting. Type yes end hit Enter.

Note: We cloned the repo into the user folder. /home/ubuntu for me. Now the full project path is /home/ubuntu/pm2-deploy. We will use this path to update the ecosystem.config.js file in the next step.

And now we are good to close the remote connection to the server.

Step 5: Configuring the ecosystem.config.js file

Now that we have a remote server up&running and have already pushed the project into our repository, we need to properly configure the ecosystem.config.js file to tell PM2 where our project is, what to do with that, and where to push that.

The file will look like this:

Notice there are 2 sections we are exporting:

  • apps
  • deploy

The name field in the apps section is the name of our project which will be shown in PM2 process list.

The script field is the script that PM2 will run when we deploy the project to the remote server. In this case, it will be the same as the main field in the package.json file.

The rest of the fields are pretty self-explanatory.

  • user is the username that you use to connect to the remote server using SSH
  • host is the IP of the remote server
  • path where do you want your project to be deployed in your remote server? Remember we already cloned the repo into our remote server. We can go ahead and write that path here
  • repo is the repository URL in a format like
  • ref is the reference branch. Which branch we want the remote server to pull
  • key is the LOCAL PATH of the key that we use to connect our machine using SSH
  • "post-deploy" takes commands which will be run at the remote machine after pulling the repo from Github

Step 6: Deploying

We have configured our machine and PM2. We can now deploy our project to the remote machine.

Before deploying we need to commit and push the changes we have made. After that, for the first run, we need to tell PM2 that it needs to setup the project.

pm2 deploy ecosystem.config.js production setup
Enter fullscreen mode Exit fullscreen mode

With this command PM2 connects to the remote, clones the repo from Github. We can now deploy the project.

pm2 deploy ecosystem.config.js production
Enter fullscreen mode Exit fullscreen mode

PM2 deploy success output

Now you are asking yourself: Now what?
Well, we didn't set up a server like nginx but we can test if the project is working or not with curl. Of course, we need to connect to the remote machine before doing that.

curl http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

If you see the index.html output on the screen that's great news! You have done it!

And also you can list the apps PM2 running with this command

pm2 ls
Enter fullscreen mode Exit fullscreen mode


We made great progress here. We learned how to deploy our project with just one command.

Here's the sample Repo:

I know I didn't tell you how to install nginx and serve the port we are using for our project but I will definitely do that in the near future and update here.

If you have any issues with anything, feel free to tell me what's wrong on the comments section.

Discussion (0)

Editor guide