CI/CD Pipelines: Beginner's Blog Tutorial
CI/CD Pipelines

CI/CD Pipelines: Beginner's Blog Tutorial

19 August 20265 min read920 words
Tags#ci-cd#github-actions#devops

CI/CD sounds like enterprise jargon, but the idea fits in one sentence: every time you push code, a machine checks it and, if everything passes, ships it. No "works on my machine", no Friday-evening manual deploys. This tutorial builds a real pipeline with GitHub Actions, from your first green checkmark to an automatic deployment. Every workflow in this guide has been run before it was written down.

The two halves, in plain words

  • CI — Continuous Integration: on every push, install dependencies, run the linter, run the tests. Broken code is caught in minutes, not discovered by a colleague next week.
  • CD — Continuous Deployment: when the checks pass on your main branch, the new version goes live automatically.

We use GitHub Actions because it is built into GitHub, free for public repositories, and comes with a generous free allowance for private ones. The concepts transfer directly to GitLab CI, Bitbucket Pipelines and others.

What you need

  • A GitHub account and a repository with a small Node.js project (any project works; adjust the commands to your stack)
  • A package.json with a test script — even one passing test is enough to start

Step 1: Your first workflow

A pipeline is a YAML file in your repository under .github/workflows/. Create .github/workflows/ci.yml:

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm test

Commit and push it. Open the Actions tab of your repository: a run is already going. Line by line, this file says:

  • on: — run this on every push to main and on every pull request.
  • runs-on: ubuntu-latest — GitHub starts a fresh Linux machine for every run. Nothing from previous runs survives, which is exactly the point: the pipeline proves your project builds from scratch.
  • actions/checkout — clones your code onto that machine.
  • actions/setup-node — installs Node.js 22 and caches your npm downloads between runs.
  • npm ci — installs exactly what package-lock.json specifies. In pipelines, always npm ci, never npm install.
  • npm test — the actual check. A non-zero exit code fails the run and paints the commit red.

Step 2: Add a lint step

Tests tell you the code works; a linter tells you it is consistent. Add a step before the tests:

      - run: npm run lint
      - run: npm test

Order matters for speed: linting takes seconds, so let it fail fast before the slower test suite runs. The pipeline stops at the first failing step.

Step 3: Protect your main branch

A pipeline nobody has to obey is decoration. In your repository settings, open Branches → Add branch ruleset and require the CI check to pass before merging. From now on, a red pull request physically cannot be merged. This one setting is where the real culture change happens: the pipeline stops being advice and becomes the gate.

Step 4: Secrets — never in the YAML

Deployments need tokens and keys. They do not go in the workflow file; they go in Settings → Secrets and variables → Actions. In the workflow you reference them like this:

      - run: npx some-deploy-tool
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

GitHub masks secret values in logs. Two habits on top of that:

  • Scope tokens as narrowly as the provider allows (one project, one permission).
  • If a secret ever lands in a commit, rotate it immediately. Deleting the commit does not unpublish it.

Step 5: The D — deploy automatically

The simplest honest setup for a website: connect your repository to a hosting platform like Vercel, Netlify or Render. They watch your main branch and deploy on every push, so your "CD" is one integration click, and your CI ruleset from step 3 guarantees only green code reaches main.

When you outgrow that and want the deploy inside your own pipeline, add a second job that only runs on main, after the tests:

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "run your deploy command here"
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

needs: test chains the jobs: deploy waits for tests and is skipped when they fail. The if: line keeps pull requests from deploying.

Step 6: Read a failing run

Sooner or later the checkmark turns red. The debugging routine:

  • Open the run in the Actions tab and click the failing step. The log shows exactly what the machine saw.
  • Reproduce locally: run the same command (npm ci && npm test) in a clean state. "Works locally, fails in CI" is almost always a file you forgot to commit, an environment variable that only exists on your machine, or a version difference.
  • Pin what the pipeline proved wrong: if CI caught a dependency missing from package.json, that is the pipeline doing its job.

Habits that keep pipelines pleasant

  • Keep it under five minutes. A slow pipeline gets ignored or bypassed. Cache dependencies, split slow suites.
  • Fix red immediately. A main branch that stays red for a day teaches everyone that red is normal.
  • One workflow file per purpose. A ci.yml for checks, a separate file for scheduled jobs. Small files stay readable.
  • Add a status badge to your README so the state of main is visible at a glance:
![CI](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg)

Where to go next

  • Add a build step (npm run build) so broken production builds are caught before deploy, not during.
  • Containerising your app first? The pipeline can build and push a Docker image — our Docker tutorial covers the image side.
  • Deploying to functions instead of servers? See the serverless tutorial, and browse the rest of the Cloud & DevOps chapter.

Did a workflow in this guide fail on your repository? Send us the failing step — we retest and correct reported issues.

Comments

No comments yet. Be the first to share your thoughts.

CI/CD Pipeline Tutorial with GitHub Actions (2026)