How I set up Travis CI to publish to NPM

I was faced with a challenge, to automatically create a new package version and publish code to NPM after a Pull Request was merged on GitHub. After some tinkering, I made a solution using Travis CI. Here’s how it works.


  • A GitHub account
  • A Travis CI account (connect with GitHub)
  • A NPM account
  • Your repository needs to be set to public (only needed if you have the free plan on Travis CI)

Initial Configuration

First, go to NPM and create a new token:

Make sure it’s an Automation token, so that 2FA is not asked (used for CI/CD purposes).

Make sure to create an “Automation” token

Copy the contents of the token (this will only be showed ONCE, so make sure to copy it now) and go to your Travis CI dashboard.

A quick note on Travis CI

Travis is currently moving from using to I used the latter, as it will be the default one moving forward, and that is the one we’re going to be assuming for this post.

On your Travis dashboard, go to the repository you want to configure, and click on More Options > Settings

Click on More Options > Settings

Under Environment Variables , create two variables:

  • NPM_TOKEN > the token you copied from NPM
  • NPM_EMAIL > the email address from your NPM account (not sure if this needs to be the actual address you used, but I haven’t tested using a different one)
Environment variables on Travis Dashboard

Setting up the jobs

  • Test > Runs npm test
  • Version > Runs npm version to create a new version of the package
  • Release > Runs npm publish to release the new package to NPM

A note on the Version job

This job will create a new version of your package automatically and push the new tag to GitHub. You can skip this if you want to do it manually. It depends on how your workflow is setup.

These jobs will be configured on a .travis.yml file on the root of your project:

Example .travis.yml

Let’s go through each part of the file.

First part

The first part is only describing which type of project this is and the tools to use. Since this is a Node project, we set up the node_js property, and here we have it configured to use version 12.14 . If you want to read more about the available properties on this file, go to the official documentation for Travis.

The first job we’re configuring is called Test. This is automatically run on a Travis build, but I like having things explicit in code, so that it’s easier to understand what’s going on at each stage.

Travis Test stage

The second job is Version , and this is optional as it will automatically version your package and push a new tag to GitHub. If you want to tag your package manually on your workflow, skip this step.

Travis Version stage

Note that for this script to work, you need a GitHub deploy key, so that Travis can push the tags to your repository.

Add GitHub deploy key to Travis

Note: You can add the openssl script to your before_install if you want it to run before every stage, or you can add it as part of the Version stage as I did on my .travis.yml .

The final job is Release , which will publish our NPM package accordingly.

Travis Release stage

The Release stage is set to only run if a tag is present, and the commit message matches the RegEx /^Version /. Notice the use of $NPM_EMAIL and $NPM_TOKEN , those are the variables we set on the first steps of this post.

Note that we didn’t specify for it to run on branch master , that’s because pushing the tags to the repo creates a separate build with a commit detached from any branches. That’s why we check for the tag presence and the commit name (should match what we specified on the Version step).

And lastly, make sure skip_cleanup is set to true and you have before_deploy: “npm run build" , otherwise your dist folder will not be sent to NPM.

Before Deploy tag

So with this setup, this is the workflow you can expect:

  • Checkout a new branch from master , work on it and push to remote
  • Create a PR pointing to master . This will trigger the test stage, because it runs on every commit
  • After PR is merged, version will be triggered, which will version the package and push a new commit to master with the commit message Version x.x.x (where x will be replaced with your actual version numbers)
  • The new commit will trigger release , which will publish the package to NPM

One thing to note is that Version only runs on commits that do not match the RegEx /^Version / . Meaning any commit that matches Version ... will be skipped. This is so that we don’t create an infinite loop where we publish a commit to master using Version, and that in turn triggers Version again and again.

This allows for you to create a new patch version on every PR. Of course, this means that major or minor versions need to be created manually. In our case, that wasn’t necessary, as every new version we release is a patch.

You could configure your steps in a way that it assumes which new version you want based on the commit message for example, or you can set up a release branch that will trigger the release everytime a tagged commit is sent to it. You should adapt this method to your workflow, to meet your demands.

Thank you for reading! See you on the next one!

Bruno Duarte Brito. Race car driver? Twitch streamer? Software engineer? Who knows…