How to Set Up CI/CD for a Node.js Project Using GitHub Actions

Set up a CI/CD pipeline for Node.js with GitHub Actions. Automate tests, linting, Dependabot updates, and deploy via SSH and Docker.

Continuous Integration and Continuous Deployment (CI/CD) are essential for modern development. In this guide, I'll walk you through setting up a full CI/CD pipeline for a Node.js project using GitHub Actions. We will cover automated testing, linting, Dependabot for dependency updates, and deploying to a VPS using SSH and Docker.

Prerequisites

Before we start, ensure you have:

  • A Node.js project hosted on GitHub.
  • A VPS with SSH access and Docker installed.
  • A GitHub Actions workflow directory (.github/workflows/).
  • A GitHub personal access token for Dependabot.

Step 1: Setting Up Dependabot

Dependabot automates dependency updates. Create a .github/dependabot.yml file:

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "daily"
    open-pull-requests-limit: 5

Commit and push this file to enable automated dependency updates.

Step 2: Defining the CI Workflow

Create a new workflow file at .github/workflows/ci.yml:

name: CI Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18
      - name: Install dependencies
        run: npm install
      - name: Run linter
        run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18
      - name: Install dependencies
        run: npm install
      - name: Run tests
        run: npm test

This workflow:

  • Runs on every push and pull request to main.
  • Checks out the repository.
  • Installs dependencies.
  • Runs the linter and tests.

Step 3: Adding Deployment Workflow

Create a new workflow file at .github/workflows/deploy.yml:

name: Deploy to VPS

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Build Docker image
        run: |
          docker build -t my-node-app .
      - name: Push Docker image
        run: |
          echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
          docker tag my-node-app mydockerhubuser/my-node-app:latest
          docker push mydockerhubuser/my-node-app:latest
      - name: Deploy via SSH
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.VPS_SSH_KEY }}
          script: |
            docker pull mydockerhubuser/my-node-app:latest
            docker stop node-app || true
            docker rm node-app || true
            docker run -d --name node-app -p 3000:3000 mydockerhubuser/my-node-app:latest

This workflow:

  • Runs on pushes to main.
  • Builds a Docker image.
  • Pushes it to Docker Hub.
  • Connects to the VPS via SSH and deploys the container.

Step 4: Storing Secrets in GitHub

For security, store credentials as GitHub Secrets:

  • DOCKER_USERNAME – Your Docker Hub username.
  • DOCKER_PASSWORD – Your Docker Hub password.
  • VPS_HOST – Your VPS IP or domain.
  • VPS_USER – Your SSH username.
  • VPS_SSH_KEY – Your SSH private key.

Go to Settings > Secrets and Variables > Actions in your GitHub repository and add these values.

Conclusion

With this setup, every push to main triggers automated tests, linting, and deployment to a VPS. Dependabot keeps dependencies updated, ensuring security. This CI/CD pipeline enhances reliability and automates your workflow effectively.

More posts in DevOps