Publishing npm packages to multiple registries with GitHub actions
Tags: npm, githubactions, node, javascript
Published: 2021-03-14 17:49:34

---
title: Publishing npm packages to multiple registries with GitHub actions
published: true
date: 2021-03-14 17:45:00 UTC
tags: ['npm', 'githubactions', 'node', 'javascript']
canonical_url: https://sevic.dev/npm-publish-github-actions/
---

This blog post covers what you need to know to automate publishing an npm package to Npm and Github package registries. It can also be helpful if you want to publish a package only into one of the mentioned registries.

### Github actions

[Github action](https://sevic.dev/notes/github-actions-101/) is a CI/CD tool integrated within Github repositories that can run different kinds of jobs (building, testing, deployment) when code is pushed to specific branches. The configuration file should be stored in `.github/workflows` inside the package repository.

### Package registries

There are two main npm package registries, Npm and Github package registries (GPR), which are available at [registry.npmjs.org](https://registry.npmjs.org/) and [npm.pkg.github.com](https://npm.pkg.github.com) respectively.

The scope lets you group the packages (e.g. `@OWNER/PACKAGE`). It is required for every published package at GPR, and it is optional to use at the Npm package registry. In this article, both of the registries will use the scope.

### Prerequisites for publishing

To publish packages with Github actions, using an access token is required. For Npm new access token can be generated on the Access Tokens page, `Automation` access token is the most suitable for CI/CD pipeline. For Github, generated [personal access token](https://github.com/settings/tokens) should have `repo` and `write:packages` scopes.

To avoid exposing the credentials in the codebase, the Github action configuration file should use repository secrets. The package version should be incremented regarding the previously published version.

### Publishing

`publish` job contains commands for setting up the default registry, auth tokens and running the `publish` script.

```yml
# .github/workflows/config.yml
# ...
jobs:
  # ...
  publish:
    needs: lint-test-audit
    runs-on: ubuntu-latest

    steps:
      # ...
      - name: Set package registry
        run: npm config set registry https://npm.pkg.github.com
      - name: GitHub package registry authentication
        run: npm set //npm.pkg.github.com/:_authToken ${{ secrets.GPR_TOKEN }}
      - name: Npm registry authentication
        run: npm set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
      - name: Publish the package to Github and Npm package registries
        run: npm publish
```

The `postpublish` npm script will trigger publishing to the Npm package registry.

```json
{
  "scripts": {
    "postpublish": "npm run publish-npm",
    "publish-npm": "npm publish --access public --ignore-scripts --@OWNER:registry='https://registry.npmjs.org'"
  }
}
```

### Package installation

After successfully publishing the public package, taking into account that the latest published versions of the package in both of the registries are the same, the package can be installed locally without any additional setup, and it will use the Npm package registry as the default one.

If the user wants to install the package from GPR, the scoped registry has to be configured, and the user has to be logged in to the registry.

```bash
npm config set @OWNER:registry https://npm.pkg.github.com
npm login --scope=@OWNER --registry=https://npm.pkg.github.com
npm i @OWNER/PACKAGE
```

### Example

A working example is available at [https://github.com/zsevic/orbit-pdf](https://github.com/zsevic/orbit-pdf)

### Further learning

- [GitHub actions 101](https://sevic.dev/notes/github-actions-101/)