Why CI/CD Still Matters in 2026

Shipping software manually is a liability. Whether you're a solo developer at a Sydney startup, a dev team at a Canadian SaaS company, or an agency shipping client projects in Singapore, inconsistent deployments lead to bugs, downtime, and wasted hours. A solid CI/CD pipeline automates your testing and deployment so that every code push goes through the same reliable process — every single time.

GitHub Actions has become the go-to tool for this in 2026. It's tightly integrated with GitHub repositories, supports reusable workflows, and has a massive ecosystem of community actions. This tutorial walks you through setting up a real, production-ready CI/CD pipeline from scratch — including automated testing, environment-specific deployments, and secret management.

What You'll Need

  • A GitHub account and a repository (public or private)
  • A Node.js or Python project (examples below use Node.js, but the pattern applies broadly)
  • A deployment target — we'll use Vercel for frontend apps and touch on Railway for backend services
  • Basic familiarity with Git and the command line
  • Around 45–60 minutes to complete the full setup

Step 1: Understand the Pipeline You're Building

Before touching any YAML, map out what you want your pipeline to do. A well-designed CI/CD pipeline typically has two phases:

  • CI (Continuous Integration): Run on every pull request — lint code, run tests, check types
  • CD (Continuous Deployment): Run on merge to main — build the app and deploy to production (or staging)

Here's the flow we're building:

Push to PR branch → Lint → Unit Tests → Type Check → ✅ Ready to merge
Merge to main → Build → Deploy to Production → Notify Slack

Pro tip: Keep CI and CD in separate workflow files. This makes debugging easier and lets you trigger them independently.

Step 2: Create Your Workflow Directory

GitHub Actions looks for workflow files inside a specific folder in your repository. In your project root, create the following structure:

mkdir -p .github/workflows

All .yml files inside .github/workflows/ are automatically detected by GitHub as workflows. You'll create two files: one for CI and one for CD.

Step 3: Write Your CI Workflow

Create a file called .github/workflows/ci.yml and add the following:

name: CI

on:
  pull_request:
    branches:
      - main
      - develop

jobs:
  lint-and-test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Run TypeScript type check
        run: npm run typecheck

      - name: Run unit tests
        run: npm test -- --coverage

      - name: Upload coverage report
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report
          path: coverage/

A few things worth noting here:

  • actions/checkout@v4 and actions/setup-node@v4 are the latest stable versions as of early 2026
  • npm ci (not npm install) is used for reproducible installs — it respects your package-lock.json exactly
  • The cache: 'npm' option dramatically speeds up repeated runs by caching your node_modules

Common pitfall: If your package.json doesn't have a typecheck or lint script defined, the workflow will fail. Make sure these scripts exist before pushing.

Step 4: Add Secrets for Deployment

Your CD workflow will need credentials — API tokens, deployment keys, environment variables. Never hardcode these. GitHub provides a built-in secrets manager.

Adding secrets to your repository

  1. Go to your GitHub repository → SettingsSecrets and variablesActions
  2. Click New repository secret
  3. Add the following (adjust for your deployment platform):
    • VERCEL_TOKEN — your Vercel API token (found in Vercel account settings)
    • VERCEL_ORG_ID — from your .vercel/project.json after linking the project
    • VERCEL_PROJECT_ID — same file as above

For backend services on Railway, add a RAILWAY_TOKEN instead. For AWS deployments, you'd add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

Pro tip: Use environment secrets (not just repository secrets) if you need different values for staging vs. production. Go to Settings → Environments to set these up.

Step 5: Write Your CD Workflow

Create a second file: .github/workflows/cd.yml

name: CD

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build application
        run: npm run build

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

      - name: Notify Slack on success
        if: success()
        uses: slackapi/slack-github-action@v1.27.0
        with:
          payload: '{"text": "✅ Deployment to production succeeded!"}'
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

The environment: production key ties this job to your GitHub Environment, enabling protection rules like required reviewers before deployment — a great safeguard for production.

Step 6: Protect Your Main Branch

CI is only useful if developers can't bypass it. Enforce status checks on your main branch:

  1. Go to Settings → Branches → Branch protection rules
  2. Click Add rule and enter main
  3. Enable:
    • Require status checks to pass before merging — select your lint-and-test job
    • Require branches to be up to date before merging
    • Require pull request reviews before merging (at least 1 reviewer)
  4. Save the rule

Now no one — including repository admins — can push directly to main without passing CI first.

Step 7: Test Your Pipeline End to End

Push your workflow files on a new branch and open a pull request against main. You should see the CI checks appear automatically at the bottom of the PR within a minute or two.

To verify everything works:

  1. Intentionally break a test — confirm CI fails and blocks the merge
  2. Fix the test — confirm CI passes and the PR becomes mergeable
  3. Merge the PR — confirm the CD workflow triggers and deploys successfully
  4. Check Slack (or your notification channel) for the success message

Common pitfall: If your workflow never appears, check that your YAML indentation is correct. GitHub Actions is extremely sensitive to YAML formatting. Use a linter like yamllint.com or the VS Code YAML extension to catch issues before pushing.

Step 8: Add Caching and Matrix Testing (Optional but Recommended)

For larger projects, you can speed up your pipeline significantly using matrix builds to test across multiple Node.js versions simultaneously:

strategy:
  matrix:
    node-version: [18, 20, 22]

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

This runs your test suite in parallel across all three versions — catching compatibility issues before they reach production. For projects targeting clients in Australia or Singapore with strict uptime requirements, this kind of thorough testing pays for itself quickly.

Common Mistakes to Avoid

  • Storing secrets in code: Even in private repos, use GitHub Secrets — never hardcode tokens in workflow files
  • Running CD on every branch: CD should only trigger on main (or a dedicated release branch). Use branch filters carefully
  • Skipping the build step in CI: Always verify the app actually builds in CI, not just that tests pass
  • Not pinning action versions: Use @v4 tags (not @main) for stability. Unpinned actions can break without warning

Next Steps

With your CI/CD pipeline running, you've eliminated an entire category of manual, error-prone work from your development process. Here's where to go from here:

  • Add end-to-end tests using Playwright or Cypress and integrate them as a separate CI job that runs before deployment
  • Set up staging environments that deploy automatically on pushes to a develop branch, giving stakeholders a preview before production
  • Explore GitHub Actions caching strategies for Docker layers, pip packages, or Turborepo's build cache to cut run times further
  • Integrate security scanning with tools like dependabot or trivy to catch vulnerable dependencies automatically

If you're building a product and want the entire infrastructure — from architecture decisions to deployment pipelines — handled properly from day one, the team at Lenka Studio works with SMBs across Australia, Singapore, Canada, and the US to build scalable, maintainable systems. Get in touch and let's talk about what your stack needs.