🚀

Release & Deployment

CI/CD pipelines, deployment strategies, feature flags, Docker, and how the best teams ship 50+ times per day without breaking production.

Deployment Strategies

How you deploy determines your risk, downtime, and ability to rollback. Each strategy trades off complexity, cost, and risk differently.

🔵🟢 Blue/Green Deployment

Two identical environments: Blue (current production) and Green (new version). Switch traffic instantly. Instant rollback by switching back.

🔵
Blue (v1.0)
Current production
100% traffic
Load Balancer
switches traffic
🟢
Green (v1.1)
New version
0% → 100% traffic
✅ Zero downtime ✅ Instant rollback ❌ 2× infrastructure cost

🐦 Canary Deployment

Gradually shift traffic to the new version. Start with 1%, watch metrics, increase to 10% → 25% → 50% → 100%. Roll back immediately if error rates spike.

v1.0 — 95%
v1.1 — 5% (canary)
Monitor for 30 min → if error rate < 0.1% → increase to 25% → 50% → 100%
✅ Real-world testing ✅ Low blast radius ❌ Complex to manage

🔄 Rolling Deployment

Replace instances one by one. At any point, some servers run the old version and some run the new. Kubernetes does this by default. No extra infrastructure needed.

v1.0
v1.0
v1.1 ✓
updating...
v1.0
5 instances → update 1 at a time → no downtime, no extra cost
✅ Amazon's Deployment Philosophy Amazon deploys to production every 11.6 seconds on average. Their "Correction of Errors" (COE) process treats every failed deployment as a learning opportunity. They use canary deployments extensively and have automated rollback triggered by their monitoring within 60 seconds of anomaly detection.

Feature Flags

Decouple deployment from release. Ship code to production but control who sees it. Feature flags enable trunk-based development, A/B testing, and instant kill switches.

// Simple feature flag implementation
const flags = {
  ai_category_suggestion: isEnabled('ai_category_suggestion'),
  new_dashboard: isEnabledForUser('new_dashboard', user.id),
  dark_mode_beta: user.isBetaUser && isEnabled('dark_mode_beta'),
};

// In component
function ExpenseForm() {
  const { ai_category_suggestion } = useFeatureFlags();
  return (
    <div>
      <NoteField />
      {ai_category_suggestion && <AISuggestionChip />}
    </div>
  );
}

// Use LaunchDarkly, Flagsmith, or PostHog for production
// They support: percentage rollout, user targeting, A/B tests
Flag TypePurposeExample
Release toggleHide unfinished features in productionNew checkout flow — 0% until ready
Experiment toggleA/B test different implementations50% see "Add" button, 50% see "Record"
Ops toggleKill switch for problematic featuresDisable AI API calls if Groq is down
Permission toggleEnable for specific users/rolesPremium features for paid users only

Docker & Containerization

Containers solve the "works on my machine" problem by packaging code with its exact dependencies. Docker has become the standard unit of deployment.

# Multi-stage Dockerfile — production-optimized
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Stage 2: Production image (much smaller)
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

# Result: 50MB image vs 900MB single-stage

Semantic Versioning (SemVer)

VersionTypeWhen to bumpExample change
2.0.0MAJORBreaking API changesRename endpoint, change response format, drop support
2.1.0MINORNew backward-compatible featuresAdd new optional field, new endpoint, new flag
2.1.3PATCHBug fixes onlyFix crash, fix wrong calculation, security patch
2.1.3-beta.1Pre-releaseTesting a future releaseAlpha, beta, rc1 before official release
💡 Automate Versioning with Conventional Commits Tools like semantic-release parse your commit messages and automatically bump versions: feat: → MINOR, fix: → PATCH, feat!: or BREAKING CHANGE: → MAJOR. Then auto-publish to npm and create GitHub releases. Zero manual version management.