Manoj
←Back to Blog
·4 min read

GitHub Actions: Building a Useful CI Pipeline

Build a practical pnpm CI workflow with reproducible installation, useful checks, minimal permissions, and clear failure signals.

github-actionsci-cdpnpmdeveloper-experience

GitHub Actions: Building a Useful CI Pipeline

A CI pipeline is useful when it answers a concrete question: can this change be integrated without breaking the checks the team relies on?

It does not need a long list of jobs to look serious. Start with the commands developers already run, make the environment reproducible, and ensure failures tell someone what to fix. A quick, understandable pipeline is more valuable than an impressive workflow nobody trusts.

Make local commands the interface

Define linting, formatting checks, tests, and production builds in the package scripts. The workflow should call those scripts rather than maintain a second implementation of the same rules.

For a small Next.js project, the initial sequence might be frozen installation, lint, format check, and build. If the application has meaningful automated tests, include them too. A successful build catches compilation problems, but it does not prove a checkout flow or permission rule behaves correctly.

Keep formatting verification separate from automatic rewriting. CI should report a formatting problem clearly; it should not silently alter the proposed change.

Use the same runtime and package manager

Record the package manager version in package.json and select a supported Node version intentionally. Unexpected differences between a laptop and CI create failures that are hard to reproduce.

Commit the lockfile and install with pnpm install --frozen-lockfile. The command should fail when the manifest requires a lockfile update rather than resolving a different dependency tree during verification. See pnpm's installation reference.

An illustrative workflow for this style of project is:

name: CI

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

permissions:
  contents: read

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: pnpm/action-setup@v6
      - uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm format:check
      - run: pnpm build

The example assumes the repository declares its pnpm version and those scripts. It is an illustration, not a change to this site's deployment workflow. Review action versions when adopting it; pinning actions to reviewed commit SHAs gives tighter control than mutable major tags.

Cache downloads without changing correctness

Dependency caching should reduce repeated downloads, not become a prerequisite for a successful run. A cold cache must still produce the same result.

Set up pnpm before asking setup-node to configure its pnpm cache. The action's documentation explains cache inputs and package-manager setup requirements.

Do not assume cached dependencies replace installation. Keep the frozen install step so that the workspace matches the committed manifest and lockfile. If caching fails or misses, the workflow should become slower rather than incorrect.

Put fast feedback where it helps

For a small repository, one job running checks sequentially is often enough. It avoids repeating setup and makes the output easy to follow. Put inexpensive checks before the production build when they can catch common mistakes early.

Split jobs when independent checks are expensive enough to justify parallel setup, or when separate ownership makes failures easier to understand. Measure runtime before redesigning the pipeline around a theoretical speedup.

Use descriptive step names as the workflow grows. A failure called type check or integration tests gives a reviewer a better starting point than a generic script failure buried in a large shell block.

Keep privileges tied to the job

Verification normally needs repository read access, not deployment credentials or permission to write commits. Grant additional capabilities only to the jobs that require them.

GitHub documents GITHUB_TOKEN permissions and how to configure them. Treat changes to workflows and action dependencies as code that deserves review.

Pull requests should be checkable without production secrets. Use test configuration or isolated services for checks that need dependencies, and make missing optional integrations explicit.

Keep verification and release decisions understandable

A green pipeline is evidence about the checked revision. Make sure the revision deployed is the one whose checks matter, particularly when an automated version commit follows verification.

After introducing CI, deliberately submit a formatting error or failing check on a test branch and confirm the failure is visible. Then document the matching local command. The pipeline succeeds when it shortens the path from a broken change to a clear fix.