Simple CI/CD Pipeline Implementation

So here’s what happened: I was fixing a simple UI bug on my website when I made one of those classic developer mistakes. I pushed a commit without double-checking my changes, and somehow convinced myself that Vercel’s built-in pipeline would catch any issues. Spoiler alert - it didn’t.

The site went down, and I spent the next hour frantically rolling back changes while my perfectionist brain screamed at me. That’s when I realized I needed to stop relying on Vercel’s basic checks and build something more robust.

100%
sequenceDiagram participant Developer participant VCS as Version Control System participant CI as CI System participant Production Developer->>VCS: Commit code VCS-->>CI: Trigger build CI->>CI: Run tests alt Tests pass CI->>Production: Deploy else Tests fail CI->>Developer: Notify failure end

Basic CI/CD pipeline flow.

What I Actually Wanted to Achieve

My personal website is pretty straightforward - it’s an Astro project stored on GitHub and deployed through Vercel. After my embarrassing deployment failure, I had some clear goals:

I’m keeping it simple for now. End-to-end testing and performance monitoring are definitely on my list, but I wanted to start with the basics and actually ship something that works.

The Basics of CI/CD (Without the Buzzwords)

Look, CI/CD sounds fancy, but it’s really just automation that saves you from yourself. Continuous Integration means your code gets tested every time you make changes. Continuous Deployment means those changes go live automatically once they pass all checks.

The whole point is catching problems early instead of discovering them when your site is down and you’re stress-eating cereal at 2 AM.

💡 Real Talk

CI focuses on merging everyone's code regularly and testing it together. CD makes sure you can deploy safely anytime without breaking things. It's basically having a really paranoid assistant who double-checks everything.

Setting This Thing Up

Let me walk you through exactly how I built this pipeline. I’ll skip the theoretical stuff and jump straight into what actually works.

Getting GitHub Actions Running

First, you need to create the workflow structure in your repo:

.github/
└── workflows/
    └── ci.yml

The workflow file is where the magic happens. Here’s what I ended up with after some trial and error:

name: CI

on:
  push:
    branches:
      - '*' 
  pull_request:
    branches:
      - 'main'  

jobs:
  build:
    runs-on: ubuntu-latest

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

      - name: Install dependencies
        run: npm install  

      - name: Run tests
        run: npm test

      - name: Build
        run: npm run build 

This runs on every push to any branch and every pull request to main. Probably overkill, but I’d rather be safe than sorry at this point.

⚠️ Heads Up

Make sure your npm scripts actually exist before setting this up. I definitely didn't spend 20 minutes debugging a missing 'test' script. Nope, not me.

Branch Protection Rules (AKA Saving Yourself from Yourself)

GitHub’s branch protection is honestly a lifesaver. Here’s how to set it up:

  1. Go to your repo’s Settings → Branches
  2. Click “Add rule”
  3. Type in your main branch name
  4. Check “Require pull request reviews before merging”
  5. Check “Require status checks to pass before merging”
  6. Select your CI workflow from the list

Now you literally can’t push broken code to main, even if you try. Past me would have found this annoying, but current me appreciates the guardrails.

🛡️ Pro Tip

Branch protection rules are your safety net. They make sure code gets reviewed and tested before it hits your main branch. Trust me, you want this.

How This Actually Works in Practice

Here’s what happens when I push code now:

My CI/CD Pipeline in Action

100%
sequenceDiagram participant Developer participant VersionControl as GitHub participant CI_System as GitHub Actions participant Staging participant Production Developer->>VersionControl: Push code VersionControl-->>CI_System: Trigger workflow CI_System->>CI_System: Install dependencies CI_System->>CI_System: Run tests CI_System->>CI_System: Build project CI_System-->>VersionControl: Report status alt If everything passes CI_System->>Staging: Deploy to staging Staging-->>CI_System: Deployment confirmed CI_System->>Production: Deploy to production else If something fails CI_System->>Developer: Send failure notification end

What actually happens when I commit code now.

Breaking Down Each Step

  1. I push code - Same as always, but now I actually check what I’m pushing
  2. GitHub triggers the workflow - Happens automatically within seconds
  3. Dependencies get installed - npm install runs in a clean environment
  4. Tests run - Any automated tests I’ve written get executed
  5. Build happens - The Astro build process runs to make sure everything compiles
  6. Status gets reported - I get a green checkmark or a very red X

If anything fails, the deployment stops and I get notified. No more broken production sites.

100%
graph TD; A[I Push Code] -->|GitHub detects change| B[GitHub Actions starts]; B -->|npm install| C[Install Dependencies]; C -->|npm test| D[Run Tests]; D -->|npm run build| E[Build Project]; E -->|All good?| F{Status Check}; F -->|✅ Pass| G[Deploy to Production]; F -->|❌ Fail| H[Slack notification of shame];

The actual flow from my perspective.

The beauty of this setup is that it’s completely automated. I don’t have to remember to run tests or check if my build works - it just happens. And if I mess up, I know about it immediately instead of finding out when someone tells me my site is broken.

💡 Reality Check

This pipeline catches the obvious stuff - syntax errors, missing dependencies, broken builds. It won't catch logic bugs or design issues, but it'll stop you from deploying code that literally doesn't work.

What I Learned

Building this pipeline was honestly easier than I expected, but it’s already saved me from myself at least three times. No more late-night panic fixes, no more wondering if my latest changes broke something.

The next step is adding some actual end-to-end tests, probably with Playwright or Cypress. I also want to set up proper staging deployments and maybe some performance monitoring. But for now, this basic setup gives me the confidence to push code without holding my breath.

  1. GitHub Actions Documentation - surprisingly readable
  2. Vercel Documentation - for deployment integration
  3. GitHub Actions Marketplace - tons of pre-built actions

If you’re setting this up yourself and run into issues, feel free to reach out. I probably made the same mistake already.

Stay up to date

Get notified when I publish something new, and unsubscribe at any time.

Join 44 other subscribers.

Contact Pavlin Gunov at contact@pavlinbg.com

Phone: +1234567890

Address: Sofia, Bulgaria

© 2025 Pavlin

Instagram GitHub