GitHub Actions Tutorial — Project: Node.js CI

1 minute read

Project: Node.js CI Pipeline

Build a complete CI pipeline for a Node.js project with linting, testing across multiple Node versions, coverage reporting, and build artifact upload.


Requirements

Feature Implementation
Trigger on push and PR on: push + on: pull_request
Test on Node 18 and 20 matrix.node-version
Cache npm dependencies actions/setup-node cache
Run lint + test + build Separate steps
Upload coverage report actions/upload-artifact
Fail fast on lint errors Lint runs before test matrix

Complete Workflow


name: Node.js CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

permissions:
  contents: read

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci
      - run: npm run lint

  test:
    needs: lint
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20]
      fail-fast: false
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - run: npm ci
      - run: npm test -- --coverage

      - name: Upload coverage
        if: matrix.node-version == 20
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report
          path: coverage/
          retention-days: 14

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci
      - run: npm run build

      - uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/
          retention-days: 7


Design Decisions

Decision Reasoning
Lint before test matrix Fail early — don’t waste matrix cycles on lint errors
fail-fast: false See results for all Node versions, not just the first failure
Coverage only on Node 20 One report is enough; avoids duplicate artifacts
Separate build job Only runs if all tests pass
14-day coverage retention Long enough for review; shorter than default 90 days

Expected Output

✅ lint (15s)
  ✅ npm run lint — 0 errors, 0 warnings

✅ test (Node 18) (45s)
  ✅ 42 tests passed

✅ test (Node 20) (43s)
  ✅ 42 tests passed
  ✅ Coverage report uploaded

✅ build (20s)
  ✅ Build artifact uploaded (dist/)

Verification

After the workflow runs:

  1. Check the Actions tab — all jobs should be green
  2. Download the coverage-report artifact and open coverage/index.html
  3. Download the build-output artifact and verify the dist/ contents

← Back to: Chapter 15: Practice Projects

Next: Project — Docker + GHCR →

Updated: