Topic 68 of 75·M17
CI/CD
Senior-levelGitHub Actions · the pipeline (push → CI → tests → lint → build → deploy → migrate → restart workers) · rollback strategies
The one-sentence answer
CI/CD is the pipeline that turns a push into a deployed app — tests, lint, and build in CI; then deploy, migrate, and restart workers in CD — so shipping is repeatable instead of a manual ritual.
The mental model
The checklist's diagram:
Git push
↓
CI — tests + lint + build (automatically, on every push/PR)
↓
Deploy (on main, after CI is green)
↓
Migration
↓
Restart workers
CI answers "does this code work?" — automatically, before it merges. CD answers "is it live?" — the same tested code moves to production through a repeatable path. The pipeline makes "the last deploy" reproducible and reviewable — and rollback a known move, not a fire drill.
How it works
The CI job (GitHub Actions, as the checklist notes)
# .github/workflows/ci.yml
on:
push: { branches: [main] }
pull_request:
jobs:
test:
runs-on: ubuntu-latest
services:
mysql: # spin up the services the app needs
image: mysql:8
env: { MYSQL_DATABASE: laravel_test, MYSQL_ALLOW_EMPTY_PASSWORD: yes }
ports: [3306:3306]
redis: { image: redis:7, ports: [6379:6379] }
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with: { php-version: '8.3', extensions: pdo_mysql, redis }
- run: composer install --no-interaction
- run: cp .env.ci .env
- run: php artisan key:generate
- run: php artisan migrate --env=testing
- run: php artisan test # the whole test suite
- run: npm ci && npm run build # the frontend (Inertia, Lesson 69)
The job provisions its own services (MySQL, Redis in containers), so every push gets the same environment — the "it works on my machine" failure mode is dead.
The CD path — from green CI to production
merge to main (CI green)
↓
deploy step: release dir + symlink, composer install --no-dev, npm build
↓
php artisan migrate --force # schema first (Lesson 66)
php artisan optimize # config + route + view cache (Lesson 67)
php artisan queue:restart # workers pick up the new code
↓
smoke test: GET / health check
The order is the Lesson 66 sequence — migrate before restarting workers, caches after code — encoded in the pipeline so nobody forgets it.
Lint & static analysis
# in CI, alongside tests:
vendor/bin/pint --test # Laravel Pint — style/lint
vendor/bin/phpstan # static analysis — type errors before they ship
# fail the build on violations — CI is the gate, not a reportRollback strategies (the checklist's ask)
| Scenario | The move |
|---|---|
| Code regression (bad feature, broken route) | Instant rollback: point the release symlink back to the previous release — the code reverts in seconds; re-deploy the fix properly |
| Bad migration (schema destroyed data) | The pipeline can't undo data — restore the DB backup, then roll back code (Lesson 66's "data needs a plan") |
| Workers on bad code | queue:restart runs them on the reverted release — the rollback must include the worker restart |
| Vercel-style infra | Instant rollback to the previous deployment (this repo's own rule — Lesson 66/CLAUDE.md) |
The senior principle: code rolls back instantly, data rolls back only as far as your last backup. A pipeline that includes rollback as a step — not an incident — is the difference between a deploy hiccup and a production incident.
Interview questions
Q1. What does CI/CD mean for a Laravel app?
CI is the automated gate — tests, lint, build on every push/PR, with the services (MySQL, Redis) provisioned per job. CD is the automated ship — on green main, deploy, migrate, cache, restart workers, smoke test. The pipeline makes "does it work" and "is it live" repeatable instead of manual.
Q2. What's in a Laravel CI job?
Checkout, set up PHP with the right extensions,
composer install, the test database (migrate), the test suite, frontend build if there's one (Inertia/React), and lint/static analysis (Pint, PHPStan). Services like MySQL and Redis run as containers per job so the environment is identical every time.
Q3. What's the CD sequence?
On green main: release the code,
composer install --no-dev --optimize-autoloader, run migrations (--force), cache config/route/views, restart queue workers, then a smoke test. The order is deliberate — schema before code, workers last (Lessons 66–67).
Q4. Why do workers restart in the pipeline?
Workers are long-lived processes holding the previous release in memory (Lessons 26–27). Without the restart step, the queue keeps executing old code against the new schema. It's the step people forget — which is exactly why it belongs in the pipeline, not in memory.
Q5. How do you roll back?
For code: instant — the release symlink points back to the previous release, workers restart, done. For data: only as far as the last backup — a destructive migration needs a restore, which needs a backup made before the deploy. The senior rule: code rolls back in seconds; data rolls back as far as your backups — plan both in the pipeline.
Senior follow-up: When does CI stop being enough?
When the tests don't match production — a CI that tests one PHP version but deploys another, or tests SQLite but runs MySQL, or skips the frontend build. The senior move is parity: same PHP version, same DB engine, same build steps as production. CI's promise is "green here means green in prod" — parity is what keeps the promise.
Common mistakes
❌ Migrations after the new code is live — the app hits an unknown schema.
❌ No worker restart in the pipeline — old code runs in the queue.
❌ CI testing a different stack than production — SQLite tests, MySQL prod.
❌ No rollback plan — the first bad deploy becomes the incident.
❌ Deploying manually "just this once" — the pipeline exists to make every deploy identical.
Quick revision notes
- CI = gate (tests + lint + build, services provisioned) · CD = ship (deploy + migrate + cache + restart workers)
- Pipeline order: code →
composer install --no-dev→ migrate → optimize → queue:restart → smoke test - Workers restart in the pipeline — they hold the old release (Lessons 26–27)
- Rollback: code = instant symlink · data = as far as the backup
- Parity — CI must match production (PHP version, DB, build)
- The pipeline makes rollback a known move, not a fire drill
Check your understanding
Answer each one out loud. Then rate yourself honestly.
0/5What does CI prove, and what does CD do with it?
Recite the CD sequence and why the order matters.
Why is the worker restart a pipeline step?
What can a code rollback never undo?
What breaks CI's promise, and how do you fix it?