The Node.js Build & Publish workflow is a comprehensive, reusable GitHub Actions workflow for building, testing, and publishing Node.js applications and packages. It supports multiple package managers, various project types, and includes extensive configuration options for modern JavaScript/TypeScript development.
- ✅ Node.js 20 LTS: Optimized for Node.js 20 with support for 18.x, 20.x, 22.x
- ✅ Multiple Package Managers: npm, yarn, pnpm, bun (auto-detection)
- ✅ Project Types: Libraries, React, Next.js, Express, Monorepos
- ✅ Matrix Builds: Parallel builds across OS and Node.js versions
- ✅ Publishing: NPM, GitHub Packages, Docker registries
- ✅ Testing: Unit, integration, E2E, coverage reporting
- ✅ Code Quality: Linting, formatting, type checking, security audits
- 🚀 Monorepo Support: Lerna, Nx, Rush, Turborepo, pnpm workspaces
- 📊 Bundle Analysis: Size limits, performance budgets
- 🔒 Security Scanning: Dependency audits, vulnerability checks
- 🐳 Docker Support: Multi-stage builds, registry publishing
- 📈 Coverage Reports: Multiple formats, threshold enforcement
- ⚡ Caching: Dependencies, build outputs, custom paths
name: Build Node.js Project
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
uses: your-org/automation-templates/.github/workflows/nodejs-build.yml@main
with:
node-version: '20.x'
package-manager: 'npm'
run-tests: true
run-lint: true
upload-artifacts: truejobs:
build:
uses: your-org/automation-templates/.github/workflows/nodejs-build.yml@main
with:
# Node.js Configuration
node-version: '20.x'
package-manager: 'pnpm'
# Build Settings
build-command: 'npm run build'
build-env: 'production'
# Testing
run-tests: true
test-coverage: true
coverage-threshold: 80
# Code Quality
run-lint: true
run-typecheck: true
run-format-check: true
# Security
run-audit: true
audit-level: 'moderate'
# Bundle Analysis
analyze-bundle: true
max-bundle-size: 500
# Publishing
publish-package: true
publish-registry: 'npm'
# Docker
build-docker: true
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USER }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASS }}| Input | Description | Default | Options |
|---|---|---|---|
node-version |
Node.js version(s) | 20.x |
18.x, 20.x, 22.x |
node-version-file |
Path to .nvmrc/.node-version | '' |
File path |
| Input | Description | Default | Options |
|---|---|---|---|
package-manager |
Package manager | Auto-detect | npm, yarn, pnpm, bun |
package-manager-version |
PM version | Latest | Version string |
frozen-lockfile |
Use frozen lockfile | true |
true, false |
| Input | Description | Default |
|---|---|---|
working-directory |
Working directory | . |
build-command |
Build command | '' |
build-env |
Build environment | production |
install-command |
Custom install command | Auto-detect |
| Input | Description | Default |
|---|---|---|
run-tests |
Run tests | true |
test-command |
Test command | Auto-detect |
test-coverage |
Collect coverage | false |
coverage-command |
Coverage command | Auto-detect |
coverage-threshold |
Min coverage % | 0 |
| Input | Description | Default |
|---|---|---|
run-lint |
Run linting | false |
lint-command |
Lint command | Auto-detect |
run-format-check |
Check formatting | false |
format-command |
Format command | Auto-detect |
run-typecheck |
TypeScript check | false |
typecheck-command |
Type check command | Auto-detect |
| Input | Description | Default | Options |
|---|---|---|---|
run-audit |
Security audit | true |
true, false |
audit-level |
Audit level | moderate |
low, moderate, high, critical |
| Input | Description | Default |
|---|---|---|
analyze-bundle |
Analyze bundle | false |
bundle-command |
Analysis command | Auto-detect |
max-bundle-size |
Max size (KB) | 0 |
| Input | Description | Default | Options |
|---|---|---|---|
publish-package |
Publish package | false |
true, false |
publish-registry |
Registry | npm |
npm, github, custom |
registry-url |
Custom registry URL | '' |
URL |
publish-tag |
NPM dist-tag | latest |
latest, beta, next |
publish-access |
Access level | public |
public, restricted |
publish-provenance |
OIDC Trusted Publishing (kein NPM Token nötig) | true |
true, false |
dry-run |
Dry run | false |
true, false |
| Input | Description | Default | Options |
|---|---|---|---|
version-strategy |
Version strategy | manual |
manual, auto, semantic |
version |
Explicit version | '' |
Version string |
prerelease |
Prerelease | false |
true, false |
prerelease-identifier |
Prerelease ID | beta |
alpha, beta, rc |
| Input | Description | Default |
|---|---|---|
is-monorepo |
Is monorepo | false |
packages-path |
Packages path | packages/* |
affected-only |
Build affected only | false |
| Input | Description | Default |
|---|---|---|
build-docker |
Build Docker image | false |
dockerfile-path |
Dockerfile path | ./Dockerfile |
docker-image-name |
Image name | '' |
docker-registry |
Registry URL | '' |
| Input | Description | Default |
|---|---|---|
upload-artifacts |
Upload artifacts | true |
artifact-name |
Artifact name | nodejs-build |
artifact-path |
Paths to include | Auto-detect |
artifact-retention-days |
Retention days | 30 |
| Input | Description | Default | Options |
|---|---|---|---|
runs-on |
Runner to use | ubuntu-latest |
String or JSON array (see below) |
timeout-minutes |
Timeout | 30 |
Minutes |
The runs-on parameter supports both GitHub-hosted and self-hosted runners:
# GitHub-hosted (string)
runs-on: 'ubuntu-latest'
# Self-hosted (JSON array)
runs-on: '["self-hosted", "linux"]'
runs-on: '["self-hosted", "linux", "docker"]'See Self-Hosted Runner Documentation for details.
| Input | Description | Default |
|---|---|---|
enable-matrix |
Enable matrix | false |
matrix-os |
OS matrix (JSON) | ["ubuntu-latest"] |
matrix-node |
Node matrix (JSON) | ["20.x"] |
| Secret | Description | Required |
|---|---|---|
NPM_TOKEN |
NPM auth token | For NPM publishing |
GITHUB_TOKEN |
GitHub token | For GitHub Packages |
DOCKER_USERNAME |
Docker username | For Docker push |
DOCKER_PASSWORD |
Docker password | For Docker push |
CODECOV_TOKEN |
Codecov token | For coverage upload |
SONAR_TOKEN |
SonarCloud token | For code analysis |
| Output | Description | Example |
|---|---|---|
version |
Package version | 1.2.3 |
published |
Was published | true |
artifact-path |
Artifact path | /tmp/artifacts |
docker-image |
Docker image tag | myapp:1.2.3 |
package-manager: 'npm'
install-command: 'npm ci'
build-command: 'npm run build'
test-command: 'npm test'package-manager: 'yarn'
install-command: 'yarn install --frozen-lockfile'
build-command: 'yarn build'
test-command: 'yarn test'package-manager: 'pnpm'
package-manager-version: '8'
install-command: 'pnpm install --frozen-lockfile'
build-command: 'pnpm build'
test-command: 'pnpm test'package-manager: 'bun'
install-command: 'bun install'
build-command: 'bun run build'
test-command: 'bun test'jobs:
publish:
uses: your-org/automation-templates/.github/workflows/nodejs-build.yml@main
with:
node-version: '20.x'
build-command: 'npm run build'
run-tests: true
test-coverage: true
publish-package: true
publish-registry: 'npm'
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}jobs:
build-react:
uses: your-org/automation-templates/.github/workflows/nodejs-build.yml@main
with:
node-version: '20.x'
build-command: 'npm run build'
build-env: 'production'
test-command: 'npm test -- --coverage --watchAll=false'
analyze-bundle: true
max-bundle-size: 500jobs:
build-nextjs:
uses: your-org/automation-templates/.github/workflows/nodejs-build.yml@main
with:
node-version: '20.x'
build-command: 'npm run build'
run-typecheck: true
build-docker: true
dockerfile-path: './Dockerfile'jobs:
build-monorepo:
uses: your-org/automation-templates/.github/workflows/nodejs-build.yml@main
with:
package-manager: 'pnpm'
is-monorepo: true
packages-path: 'packages/*'
build-command: 'pnpm turbo build'
test-command: 'pnpm turbo test'
affected-only: truejobs:
matrix-build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: ['18.x', '20.x', '22.x']
pm: [npm, yarn, pnpm]
uses: your-org/automation-templates/.github/workflows/nodejs-build.yml@main
with:
node-version: ${{ matrix.node }}
package-manager: ${{ matrix.pm }}
runs-on: ${{ matrix.os }}Location: .github/config/nodejs-build/default.yml
node:
version: '20.x'
package_manager:
type: 'npm'
frozen_lockfile: true
build:
command: 'npm run build'
environment: 'production'
testing:
enabled: true
coverage:
enabled: false
threshold: 80- NPM Package:
.github/config/nodejs-build/npm-package.yml - React App:
.github/config/nodejs-build/react-app.yml - Next.js App:
.github/config/nodejs-build/nextjs-app.yml - Monorepo:
.github/config/nodejs-build/monorepo.yml
All example workflows are located in github/workflows/examples/nodejs-build/:
simple-npm-package.yml- Simple NPM package buildnpm-publish-release.yml- NPM package publishing on releasematrix-multi-version.yml- Multi-version matrix buildsreact-app-deploy.yml- React application deploymentnextjs-docker-deploy.yml- Next.js with Docker deploymentmonorepo-turborepo.yml- Monorepo with Turborepo
on:
release:
types: [published]
jobs:
publish:
uses: your-org/automation-templates/.github/workflows/nodejs-build.yml@main
with:
publish-package: true
publish-registry: 'npm'
version: ${{ github.ref_name }}
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}Ab Dezember 2025 sind npm Classic Tokens abgeschafft. Granular Tokens sind auf 90 Tage limitiert. OIDC Trusted Publishing eliminiert die Notwendigkeit von npm Tokens vollständig.
Voraussetzungen:
- npm-Account ist Mitglied der Organisation
@bauer-group - Paket existiert bereits auf npmjs.org (erster Publish muss manuell oder per Token erfolgen)
- GitHub Repository ist öffentlich ODER hat GitHub Actions Pro/Enterprise
Einrichtung auf npmjs.com:
- Auf npmjs.com einloggen
- Zum Paket navigieren → Settings → Publishing access
- Unter "Trusted publishing" auf "Add trusted publisher" klicken
- Repository-Informationen eintragen:
- Repository owner:
bauer-group - Repository name:
<euer-repo-name>(z.B.n8n-nodes-http-throttled-request) - Workflow filename:
nodejs-release.yml(der exakte Name des Release-Workflows, dernodejs-build.ymlals Reusable Workflow aufruft) - Environment: leer lassen (oder ein GitHub Environment angeben, falls verwendet)
- Repository owner:
- Speichern
Einrichtung im Caller-Workflow:
permissions:
contents: write
id-token: write # Erforderlich für npm OIDC
packages: write
jobs:
publish:
uses: bauer-group/automation-templates/.github/workflows/nodejs-build.yml@main
with:
publish-package: true
publish-registry: 'npm'
publish-provenance: true # Default, kann weggelassen werden
publish-access: 'public'
secrets: inheritWichtig: Der aufrufende Workflow muss
id-token: writein seinen Permissions haben, damit GitHub ein OIDC-Token für npm generieren kann.
Erster Publish (Bootstrap):
Beim allerersten Publish eines neuen Pakets muss dieses zuerst auf npm existieren, bevor Trusted Publishing konfiguriert werden kann.
Option A — Manuell:
npm login
npm publish --access publicOption B — Einmaliger Granular Token (90 Tage):
- Granular Token auf npmjs.com erstellen (Write, Bypass 2FA aktivieren)
- Als
NPM_REGISTRY_PUBLISH_TOKENSecret hinterlegen publish-provenance: falsesetzen- Nach erstem Release: Trusted Publishing einrichten, Token löschen,
publish-provenance: truesetzen
Fallback: Token-basierte Authentifizierung:
with:
publish-provenance: false
secrets:
NPM_REGISTRY_PUBLISH_TOKEN: ${{ secrets.NPM_REGISTRY_PUBLISH_TOKEN }}Hinweis: Granular Tokens mit Write-Berechtigung sind auf max. 90 Tage limitiert und müssen regelmäßig rotiert werden.
--provenancewird nur von npm und pnpm unterstützt. Bei yarn und bun wird das Flag ignoriert.
with:
publish-registry: 'github'
registry-url: 'https://npm.pkg.github.com'
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]with:
build-docker: true
docker-registry: 'ghcr.io'
docker-image-name: '${{ github.repository }}'
secrets:
DOCKER_USERNAME: ${{ github.actor }}
DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }}version: ${{ startsWith(github.ref, 'refs/tags/v') && github.ref_name || format('0.0.0-dev.{0}', github.run_number) }}publish-package: ${{ startsWith(github.ref, 'refs/tags/v') }}build-env: ${{ github.ref == 'refs/heads/main' && 'production' || 'development' }}coverage-threshold: ${{ github.event_name == 'pull_request' && 80 || 0 }}audit-level: ${{ github.ref == 'refs/heads/main' && 'moderate' || 'high' }}-
Package manager not detected
- Explicitly set
package-manager - Ensure lockfile exists
- Explicitly set
-
Build fails
- Check Node.js version compatibility
- Verify build command
- Review environment variables
-
Tests not running
- Verify test command
- Check test file patterns
- Review test configuration
-
Publishing fails
- Verify registry credentials
- Check package.json configuration
- Review publish access settings
Enable verbose output:
with:
build-command: 'npm run build --verbose'
test-command: 'npm test -- --verbose'- Cache dependencies: Enabled by default
- Cache build outputs: Set
cache-build: true - Use frozen lockfile: Set
frozen-lockfile: true - Matrix builds: Parallelize across versions
- Monorepo optimization: Use
affected-only: true
- Audit dependencies: Always enabled by default
- Use secrets: Never hardcode credentials
- Pin versions: Use exact versions in production
- Check licenses: Enable license checking
- Scan images: Use container scanning tools
- Convert Jenkinsfile to workflow YAML
- Map npm scripts to workflow inputs
- Configure credentials as secrets
- Set up webhooks
- Convert config.yml to GitHub Actions
- Map orbs to actions
- Update environment variables
- Configure contexts as environments
- 📚 Documentation
- 🐛 Issues
- 💬 Discussions
- 📧 Contact
This workflow is part of the Automation Templates repository and follows the same license terms.