Last updated on March 16, 2023

Automate NPM Publish Using GitHub Actions

GitHub Actions is a Continuous Integration and Continuous Delivery (CI/CD) platform that allows us to automate multiple elements of our project, like the build, test, and deployment process. We can execute these pipelines in different stages of our project; for example, when we create a pull request or generate a new commit in our GitHub repository.

Node Package Manager (NPM) is the world's largets open-source registry for JavaScript software. It contains millions of packages developers have built and used to extend their projects.

In this tutorial, we will learn the Node Package Manager (NPM) basics and its Semantic Versioning. We will understand how to use and build a GitHub Action that will automatically create and publish a new release of our npm package based on its version number (e.g. 1.0.0).

Node Package Manager Setup

Let's start by setting up our npm account. For this, we will go through the Get Started Guide of npm and create our user account. Once our setup is complete, we can publish our npm package with the command npm publish --access public (the --access flag sets the access level of your package).

Every time we publish a new version of our package, npm will require our login credentials to validate our request. To automate the publish command in our GitHub Action, we must configure how it authenticates our credentials with npm. For this, we will use the npm access tokens.

To create our access token, we will follow through the npm Create Access Token Guide. Here, we should select the token type Automation, built for automated tools like GitHub Actions or other CI/CD integrations.

Once we have generated our access token, we must store it as a GitHub secret in our project repository. GitHub secrets work as Node.js environment variables whose main objective is storing sensitive data such as passwords, tokens, and API credentials.

To create our GitHub secret, we will open our repository page, select the Settings option, and right under the Security secrets and variables, choose Actions. Here, we will click the New Repository Secret button and add our npm access token to the secret field and NPM_ACCESS_TOKEN to the name field.

We can access our secret directly from our GitHub Action using the code:

${{secrets.NPM_ACCESS_TOKEN}}

Create GitHub Action

A GitHub Action (also known as Workflow) is an automated process that runs multiple jobs in a virtual environment (Linux, Windows, or macOS). These Jobs are a set of commands executed on the same environment in the defined order (e.g. install our package dependencies with npm ci and then build our package with the command npm run build).

We will create our project's GitHub Action by adding the .github/workflows directory inside our package root folder. Inside it, we will add a new file called npm-release.yml, containing our workflow's code (this directory will include all the GitHub Actions we want to create for our project).

Let's add the following code to our npm-release.yml file:

.github/workflows/npm-release.yml
name: npm-release
on:
  push:
    branches:
      - main

Here, we added the name npm-release to our GitHub Action, and we defined our workflow trigger, which determines how and when GitHub will execute our Action's code. We can use multiple trigger events in our GitHub Action; in this case, we defined it to run every time we push a new commit into our repository's main branch.

Next, we will create our GitHub Action Job by running it in the latest version of Ubuntu.

.github/workflows/npm-release.yml
name: npm-release
on:
  push:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-latest

Then, we will define the commands (also known as steps) that we will execute in our Ubuntu environment; these steps are:

  1. Get access to our repository files: We will use the actions/checkout@v3 action, whose purpose is to add our repository files and execute our GitHub Action steps inside our project's code.
  2. Install Node.js: We will use the actions/setup-node@v3 action to install Node.js in our GitHub Action environment. Here, we can define the node version we want to use (in our case, we will use node version 16).
  3. Install project dependencies: We will install our project dependencies with the npm ci command.
  4. Build our project: We will generate the production build of our project using the npm run build command.
  5. Publish npm package release: Here we will run the npm publish --access public command to release a new version of our package. We will use our npm access token to authenticate our request by adding the environment variable NODE_AUTH_TOKEN with our GitHub Secret ${{secrets.NPM_ACCESS_TOKEN}}.
.github/workflows/npm-release.yml
name: npm-release
on:
  push:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: checkout repository
      uses: actions/checkout@v3
 
    - name: setup node
      uses: actions/setup-node@v3
      with:
        node-version: 16
        registry-url: https://registry.npmjs.org
 
    - name: install dependencies
      run: npm ci
 
    - name: build package
      run: npm run build
 
    - name: publish package npm
      run: npm publish --access public
      env:
        NODE_AUTH_TOKEN: ${{secrets.NPM_ACCESS_TOKEN}}

Once we've completed our npm-release.yml file, we can commit the changes to our project's repository. GitHub automatically detects the new commit in the main branch, triggering our GitHub Action.

Publish Workflow

The last step to complete our GitHub Action is to set up when we trigger a new release of our npm package.

Until now, every time we push a new commit into our repository's main branch, our GitHub Action is triggered, and it executes our Workflow to release a new version of our project. For GitHub to complete this Action correctly, we need to update and commit a new package version number (otherwise, npm will reject the release).

We will improve our GitHub Action using the Node Package Manager semantic versioning and Git tags.

Every Node.js project has a version number defined in the package.json file (also known as Semantic Versioning). These versions are used as a standard to differentiate the project's state by introducing major breaking changes, minor backward-compatible changes, and small patch changes (using the specification major.minor.patch. For example, 4.10.2).

  • Major updates represent breaking changes incompatible with your project's previous versions.
  • Minor updates introduce new backward-compatible features to your project.
  • Patch updates are bug fixes/patches to the existing functionality and are backward-compatible.

We will use the command npm version mayor|minor|patch to update the version number of our package and create a reference point with a new git tag. To push our changes into our project, we will use the command git push --follow-tags.

Last, we will update our GitHub Action to run every time we push a new git tag into our project's repository.

.github/workflows/npm-release.yml
name: npm-release
on:
  push:
    tags:
      - '*'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: checkout repository
      uses: actions/checkout@v3
 
    - name: setup node
      uses: actions/setup-node@v3
      with:
        node-version: 16
        registry-url: https://registry.npmjs.org
 
    - name: install dependencies
      run: npm ci
 
    - name: build package
      run: npm run build
 
    - name: publish package npm
      run: npm publish --access public
      env:
        NODE_AUTH_TOKEN: ${{secrets.NPM_ACCESS_TOKEN}}

Conclusion

Deploying an npm package using GitHub Actions is a great way to streamline your development process. In this tutorial, we learned how to create a GitHub action and use the Node Package Manager semantic versioning and git tags to automatically build and publish a new release of our npm package.