Skip to content
Latchkey

CI/CD for a Component Library with GitHub Actions

Validate, build, and publish your design-system package automatically.

A reusable component or Tailwind library ships as an npm package rather than a deployed site, so the pipeline ends in a publish rather than an upload. This recipe lints and tests on every PR, then builds and publishes to npm when you push a version tag.

What the pipeline does

  • install deps with npm ci
  • lint and typecheck
  • test with vitest
  • build ESM and CJS bundles with tsup
  • publish to npm on a version tag

The workflow

The publish job only runs on tags like v1.2.3. Set registry-url so setup-node configures auth, and provide NODE_AUTH_TOKEN from an npm automation token.

.github/workflows/ci.yml
name: CI
on:
  push:
    branches: [main]
    tags: ['v*']
  pull_request:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
          registry-url: https://registry.npmjs.org
      - run: npm ci
      - run: npm run lint --if-present
      - run: npx tsc --noEmit
      - run: npx vitest run
      - run: npm run build
  publish:
    needs: build
    if: startsWith(github.ref, 'refs/tags/v')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
          registry-url: https://registry.npmjs.org
      - run: npm ci
      - run: npm run build
      - run: npm publish --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Caching and speed

cache: npm covers installs. If you ship compiled CSS, make sure Tailwind purges unused classes via your content config so the published bundle stays small. tsup is fast, so the publish job is dominated by install; cheaper managed runners such as Latchkey keep release builds quick and inexpensive.

Deploying

Publishing means pushing the built package to a registry, not deploying a site. The workflow publishes to npm on a version tag; for a private registry, swap registry-url and the token. Pair this with Changesets to automate version bumps and changelog entries on merge.

Key takeaways

  • A library publishes to a registry instead of deploying a site.
  • Gate the publish job on a version tag (refs/tags/v*).
  • Set registry-url and NODE_AUTH_TOKEN so npm publish authenticates.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →