The CI Pipeline
The CI Pipeline
Every push runs the same gates a broken merge would skip:
name: ci
on: [push, pull_request]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm run lint && npm run typecheck
- run: npm test -- --coverage
- run: npm run build
Order matters: cheapest feedback first (lint, tsc --noEmit), then tests, then build. Use npm ci — it installs from the lockfile exactly — and cache the package manager's store so cold runs stay fast. Failing the job on any step is what makes main trustworthy.
Build, Containerize, Release
Build, Containerize, Release
Ship an artifact, not a checkout. A multi-stage Dockerfile keeps dev dependencies out of production:
FROM node:20-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
CMD ["node", "dist/server.js"]
Deployment runs migrations before switching traffic, then health checks the new version. Tag images by git SHA (app:4f9c2ab) so rollback is retagging to the previous SHA, not rebuilding. Configuration comes from the platform's environment; secrets never enter the image layer.
Production Pitfalls
Production Pitfalls
Secrets in the repo. A leaked key in git history is compromised even after deletion — use platform secret stores, rotate on exposure, and keep .env out of images with .dockerignore.
No health endpoint. Orchestrators route traffic only when /healthz answers 200; report dependency status there (database ping) so half-up instances drain.
Migrations as deploy steps. Running migrate deploy in a pre-deploy job keeps old and new code compatible with the schema — prefer additive migrations so rollback does not need a schema downgrade.
Silent config drift. Validate env with a typed schema at boot and fail fast; missing PORT should crash at startup, not at first request.
Interview: describe your pipeline stages, the rollback path, and where a migration runs relative to the traffic switch.
Quiz
1. Why run migrations before shifting traffic to a new version?
2. What does the multi-stage Docker build primarily buy you?
3. Why tag release images with the git SHA?
Flashcards
Question
Pipeline order
Click to reveal answer
Answer
lint → typecheck (tsc --noEmit) → tests → build; cheapest failure first.
Question
npm ci
Click to reveal answer
Answer
Clean install from the lockfile — required for reproducible CI.
Question
Multi-stage build
Click to reveal answer
Answer
Build in one stage, copy artifacts to a slim runtime stage.
Question
Health check
Click to reveal answer
Answer
GET /healthz returning 200 (with DB status) gates routing during rollout.
Question
Additive migration
Click to reveal answer
Answer
Schema change old code tolerates — lets rollback skip schema downgrade.
Revision Notes
Key Takeaways
- 1. Ship a built artifact tagged by commit; never deploy from a working tree
- 2. Fail fast on config at boot instead of at first request
- 3. Migrations run before traffic, secrets stay out of images
Interview Tips
- • Describe rollback end to end: previous image tag, migration compatibility, health gate
- • Say which step catches each class of failure and why that order
Cheat Sheet
lint→typecheck→test→build in CI with npm ci; multi-stage image, SHA tags; migrate deploy pre-traffic; /healthz gates rollout; secrets from platform store.