NodeJs App Build pipeline - Github Actions
Build and deploy Node.js application using Github Actions CI/CD
This article will focus on creating a basic CI/CD pipeline to build and deploy a Node.js application. It is limited to describing how to build and package Node.js code as a Docker image and publish it to the DockerHub Docker repository.
Why GitHub Actions for Node.js?
GitHub Actions offers several benefits for Node.js projects:
Native Integration: Being part of GitHub, it offers seamless integration with your repository, pull requests, and issues.
YAML-based Workflows: Workflows are defined using simple and readable YAML syntax, making them easy to create, understand, and maintain.
Extensive Marketplace: A rich marketplace of pre-built actions simplifies common tasks, from setting up Node.js environments to deploying to various cloud providers.
Cost-Effective: GitHub Actions provides free usage tiers for public repositories and competitive pricing for private repositories.
Scalability: It can handle projects of various sizes, from small personal projects to large-scale enterprise applications.
Setting Up Your Node.js GitHub Actions Workflow
Let's create a basic workflow that will:
Check out your code.
Set up the Node.js environment.
Install dependencies.
Build App.
Creating Actions Workflow in Node.js Project
Considering there is already a GitHub repository with Node.js application code published. To create an Actions Workflow for the project, create a .github/workflows
folder in your project's root directory. Inside this folder, create a new YAML file, for example, nodejs.yml
.
project-root-dir/
├── .github/
│ └── workflows/
│ └── nodejs.yml
├── src/
│ └── ...
├── package.json
├── package-lock.json
└── ...
Define Workflow
Now let’s add content to the nodejs.yml
name: Node.js CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 20.x ]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build --if-present
The above Actions Workflow has three main requirements as below
Event: The triggering source of the actions workflow. Considering the above workflow file
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
on: push and on: pull_request will trigger the workflow when there is a commit on the master branch or any pull request to the master branch.
Job: A workflow can have one or more jobs. This workflow has a single job named
build
.runs-on: ubuntu-latest
: Specifies the runner environment where the job will execute.ubuntu-latest
It is a common choice for Node.js applications.strategy:
Allows you to run the same job with different configurations.matrix:
Defines a matrix of different configurations. Here, we're testing against Node.js version 20.x. This is excellent for ensuring compatibility across different Node.js environments.
Steps: The steps are the tasks as to execute as part of Job execution in the workflow. As mentioned in the above example, the build job has 4 steps, each executes sequentially.
actions/checkout@v4
: The essential first step is to clone your repository's code onto the runner.actions/setup-node@v4
: Installs the specified Node.js version and can cache npm dependencies for faster subsequent runs.npm install
: Installs dependencies.npm run build --if-present:
Build Application.
Complete Workflow
The complete workflow to build and deploy a Node.js application as a Docker image to Docker Hub
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name: Node.js CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 20.x ]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build --if-present
publish:
runs-on: ubuntu-latest
needs: [build]
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Docker build and push
uses: docker/build-push-action@v2
with:
context: .
push: 'true'
tags: abc/your-app:latest, abc/your-app:${{ github.run_number }}
Docker File
FROM node:20-alpine
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY package*.json ./
USER node
RUN npm install
COPY --chown=node:node . .
EXPOSE 8080
CMD [ "node", "index.js" ]
The publish job in the above workflow has a few noticeable differences.
needs: Part of the publish job indicates that the job depends on the build job to be completed successfully before it starts execution.
The job also uses secrets for Docker Hub login and context variables like GitHub.run_number for image tagging. The secrets are user-defined as part of the repository settings.
Conclusion
GitHub Actions provides an incredibly versatile and powerful platform for automating the entire lifecycle of your Node.js applications. By implementing a well-defined workflow, you can ensure that your code is consistently tested, linted, and deployed, leading to higher quality software, faster release cycles, and a more confident development team. Start by automating your build and test process, and gradually expand your workflow to cover all aspects of your Node.js application's CI/CD pipeline.