← all posts

CI/CD doesn't have to be complicated on day one

·2 min read ·DevOps · CI/CD · Best Practices

CI/CD sounds like an enterprise concern. Pipelines, stages, environments, rollback strategies. If you look at what mature CI/CD setups look like, it's easy to conclude that you need a DevOps engineer and a week of setup before you can ship safely.

You don't. Here's what actually matters on day one.

The Minimum Viable Pipeline

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.4'
      - run: composer install --no-interaction
      - run: cp .env.example .env && php artisan key:generate
      - run: php artisan test --compact

That's it. Every push runs your tests. PRs that break tests don't get merged. You've caught the most common class of problems.

Add Deployment

Deployment on merge to main is the next step. For a simple VPS setup:

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - name: Deploy
        run: ssh user@server 'cd /app && git pull && composer install && php artisan migrate --force'

Automatic deploys on green tests. No manual steps. No 'I forgot to deploy' after merging.

The Parts You Can Add Later

  • Staging environments
  • Deployment previews per PR
  • Performance benchmarks
  • Security scanning

All of these are valuable. None of them are necessary on day one. The 80% solution—run tests, deploy on merge—gives you most of the safety with a fraction of the complexity.

Start simple. Add complexity when you have a specific problem to solve, not because a blog post told you that mature CI/CD looks a certain way.