contentintech

Deployment Cheatsheet

Quick reference for deployment — environment tiers, GitHub Actions and Dockerfile snippets, registry and Vercel commands, and a deployment strategy table.

CI/CDDockerVercelGitHub Actions
NotesCheatsheet

Environments

Env Purpose Data
devLocal, hot reloadMock / seed
stagingProd mirror for QAAnonymised prod
prodLive trafficReal

Build vs Runtime

Build timeRuntime
Frozen into artifactRead on process start
NEXT_PUBLIC_* (public)process.env secrets (server)

Env Vars & Secrets

# .env.local  — git-ignored, real values
DATABASE_URL=postgres://user:pass@host/db
STRIPE_SECRET_KEY=sk_live_xxx
NEXT_PUBLIC_API_URL=https://api.example.com

# .env.example — committed, keys only, no values
DATABASE_URL=
STRIPE_SECRET_KEY=
  • Never commit secrets. Never put a secret behind NEXT_PUBLIC_.
  • Prod stores: AWS Secrets Manager, Vault, GitHub secrets, platform env vars.
  • Rotate regularly, scope to least privilege.

CI/CD Pipeline

Stages (fail fast)

lint  →  test  →  build  →  deploy
(cheap, first)            (only if all pass)

GitHub Actions

# .github/workflows/ci.yml
name: CI/CD
on:
  push: { branches: [main] }
  pull_request:
jobs:
  build-and-test:
    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
      - run: npm test
      - run: npm run build
  deploy:
    needs: build-and-test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/deploy.sh
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

Docker

Image vs Container

Image = immutable blueprint (built once). Container = running instance. Many containers from one image.

Multi-Stage Dockerfile

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
USER node
CMD ["npm", "start"]

Commands

docker build -t app:$GIT_SHA .
docker run -p 3000:3000 --env-file .env app:$GIT_SHA
docker compose up -d
docker ps                       # running containers
docker logs -f <container>

docker-compose

services:
  app:
    build: .
    ports: ["3000:3000"]
    depends_on: [db]
  db:
    image: postgres:16-alpine
    environment: { POSTGRES_PASSWORD: pass }
    volumes: ["pgdata:/var/lib/postgresql/data"]
volumes: { pgdata: {} }

Registry

docker tag app:$GIT_SHA ghcr.io/acme/app:$GIT_SHA
docker push ghcr.io/acme/app:$GIT_SHA
docker pull ghcr.io/acme/app:$GIT_SHA
# tag by git SHA, not just :latest

Vercel & Cloud

Vercel CLI

vercel                # preview deploy
vercel --prod         # production
vercel env add KEY production
# Git push → auto preview per PR; main → prod; 1-click rollback

Cloud Models

ModelYou manageExample
VMOS + scalingEC2
ContainersImage + orchestrationECS, EKS
ServerlessJust codeLambda, Cloud Run

Deployment Strategies

StrategyHowTrade-off
RollingReplace a few at a timeNo downtime; two versions live
Blue-GreenSwitch all traffic at onceInstant rollback; 2x infra
CanarySmall % first, ramp upSmall blast radius; needs metrics
RecreateStop old, start newSimple; has downtime

Rollback Rules

  • Immutable, versioned artifacts → re-point, don't rebuild.
  • Backward-compatible migrations: additive first, then code.

Monitoring & Health

Three Pillars

  • Metrics — latency, error rate, throughput
  • Logs — discrete events
  • Traces — request path across services

Health Check

// app/api/health/route.ts
export async function GET() {
  try {
    await db.query("SELECT 1");
    return Response.json({ status: "ok" }, { status: 200 });
  } catch {
    return Response.json({ status: "down" }, { status: 503 });
  }
}
// liveness = process up  |  readiness = can serve

HTTPS & DNS

RecordMaps to
A / AAAADomain → IPv4 / IPv6
CNAMEDomain → hostname (custom domain)

TLS: platforms auto-provision + renew (Let's Encrypt). Redirect HTTP → HTTPS, enable HSTS.

Section navigation