DEV Community

Cover image for Publish your packages to NPM automatically with GitHub Actions
OctoLab Team
OctoLab Team

Posted on

Publish your packages to NPM automatically with GitHub Actions

Automating publication prevents manual errors, speeds up releases, and forces you to maintain a repeatable and transparent process.

In this article, we're going to create a GitHub Actions workflow that publishes to NPM when you push to main. The flow installs dependencies, runs tests, compiles, and, if all goes well, publishes the package using a secure token stored as a secret.

🎯 What is the purpose of the workflow?

Every time you merge changes to main, we want to:

  • Install dependencies
  • Run tests
  • Build the package
  • Publish to NPM using secure credentials

This standardizes the publishing process and reduces the risk of human error.

🧬 General workflow structure

name: Publish to NPM
on:
  push:
    branches:
      - main

jobs:
  publish:
    name: publish
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: "22"

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm run test

      - name: Build package
        run: npm run build

      - name: Publish to NPM
        uses: JS-DevTools/npm-publish@v3
        with:
          token: ${{ secrets.NPM_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

🛠️ What does each step do?

on: push to main
Triggers the workflow when pushing to the main branch. If you prefer to publish only with tags, you can change the trigger to on: push: tags: - ‘v*’.

actions/checkout@v4
Downloads the repository to the runner.

actions/setup-node@v4
Configures Node.js (v22 in the example). You can enable cache: ‘npm’ to speed up installations.

npm ci / npm install
Installs dependencies. npm ci is faster and more reproducible in CI if you use package-lock.json.

npm run test and npm run build
Verify that the package passes tests and compiles correctly before publishing.

JS-DevTools/npm-publish@v3
Publish the package by reading package.json. Use the token you pass through with.token.

🔐 Authentication with NPM: NPM_TOKEN

To publish, you need a token in NPM and save it as a secret in GitHub:

  1. Create an Automation Token in your NPM account (recommended for CI; respects 2FA and allows automatic publishing).
  2. In GitHub, go to SettingsSecrets and variablesActionsNew repository secret.
  3. Create the secret NPM_TOKEN with the value of the NPM token.

💡 If your package is scoped (e.g., @your-org/package), make sure that package.json contains “name”: “@your-org/package” and “publishConfig”: { ‘access’: “public” } if you want it to be public.

Example of publishConfig in package.json:

{
  "name": "@tu-org/tu-paquete",
  "version": "1.2.3",
  "publishConfig": {
    "access": "public",
    "tag": "latest"
  }
}
Enter fullscreen mode Exit fullscreen mode

🧪 Dry-run and version control

Dry-run: test the flow without actually publishing:

- name: Publish to NPM (dry run)
  uses: JS-DevTools/npm-publish@v3
  with:
    token: ${{ secrets.NPM_TOKEN }}
    dry-run: true
Enter fullscreen mode Exit fullscreen mode

Versioning: this flow publishes the version specified in package.json. Be sure to update the version before merging to main.
If you use automatic versioning (e.g., Conventional Commits + automatic releases), integrate that stage before the publication step.

✅ Final result

With this workflow:

  • You publish to NPM in a consistent and repeatable manner.
  • You avoid broken releases thanks to preliminary tests + builds.
  • You keep credentials secure with GitHub Secrets.
  • You reduce manual steps and time between merge and release.

🐙 Would you rather set it up with a visual interface?

If you're interested in defining this flow with a visual interface and getting the YAML instantly, you can use OctoLab:

  • Step-by-step visual editor
  • Dynamic fields for actions and tokens
  • Real-time YAML preview
  • Built-in validations
  • Copy/download and you're done

👉 Try it out: https://www.octolab.app/templates/npm-publish

🧵 Conclusion

Automating publication to NPM with GitHub Actions reduces friction and errors. With a simple configuration—tests, build, and a publish step with a secure token—you can standardize releases and focus on building value.

If this was helpful, let me know what you would like to add to the template (tags, prereleases, monorepos, changelogs, etc.). Let's keep going!

Top comments (0)