Modern Deployment Delivery Implementation

1. Vercel Netlify Jamstack Deployment

Platform Features Configuration Best Practices
Vercel NEW Zero-config, Edge Functions, Preview URLs, Analytics, DDoS protection, 100+ global edge vercel.json: builds, routes, headers, redirects, env vars. Auto-detect framework Optimized for Next.js. Free 100GB bandwidth. Use Edge Config for feature flags. ISR for dynamic
Netlify Edge Functions, Split Testing, Form handling, Identity auth, Deploy previews, Rollbacks netlify.toml: build command, publish dir, redirects, headers, plugins, functions Free 100GB bandwidth. Use Netlify Functions for serverless. Deploy contexts (prod/preview)
Jamstack Architecture Pre-rendered HTML, API-driven, Git-based workflow, CDN distribution, Decoupled frontend SSG with Next/Gatsby/Astro. APIs for dynamic data. Headless CMS. Build-time data fetching 99.99% uptime. 10x faster than SSR. SEO-optimized. Use webhooks for content updates
Build Optimization Incremental builds, Build cache, Parallel builds, Dependency caching, On-demand ISR Cache node_modules, .next, .cache. Turbopack (Vercel). Use buildCommand Reduce build time 50-80%. Cache restoration 10-30s. Parallel builds for monorepos
Deploy Previews PR preview URLs, Branch deploys, Unique URLs per commit, Shareable links, E2E testing Auto-deploy on PR. Comment preview URL. Delete on merge. Use for QA testing Test before production. Share with stakeholders. Run E2E tests on preview. Instant rollback
Edge Functions Serverless at edge, Low latency, Auto-scaling, A/B testing, Geo-location, Middleware Vercel Edge: /api/edge.ts. Netlify Edge: netlify/edge-functions/ Sub-10ms latency. Use for auth, redirects, A/B tests. 50ms execution limit. Lightweight only

Example: Vercel deployment configuration

// vercel.json
{
  "buildCommand": "pnpm build",
  "outputDirectory": "dist",
  "framework": "vite",
  "rewrites": [
    { "source": "/api/:path*", "destination": "https://api.example.com/:path*" }
  ],
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "X-Frame-Options", "value": "DENY" },
        { "key": "X-Content-Type-Options", "value": "nosniff" }
      ]
    }
  ],
  "env": {
    "API_URL": "@api_url_production"
  }
}

Example: Netlify configuration

# netlify.toml
[build]
  command = "npm run build"
  publish = "dist"
  
[build.environment]
  NODE_VERSION = "20"
  NPM_FLAGS = "--legacy-peer-deps"

[[redirects]]
  from = "/api/*"
  to = "https://api.example.com/:splat"
  status = 200

[[headers]]
  for = "/*"
  [headers.values]
    X-Frame-Options = "DENY"
    X-Content-Type-Options = "nosniff"
    
[[plugins]]
  package = "@netlify/plugin-lighthouse"

2. GitHub Actions CI/CD Pipeline

Component Purpose Configuration Best Practices
Workflow Triggers push, pull_request, schedule, workflow_dispatch, release, manual trigger on: [push, pull_request]. Filter branches: branches: [main] Trigger on PR for tests. Deploy on main push. Schedule nightly builds. Use paths filter
Build Job Install deps, lint, test, build, cache dependencies, parallel execution runs-on: ubuntu-latest. Use actions/setup-node@v4. Cache npm/pnpm Cache node_modules (5-10x faster). Use matrix for multi-version. Fail fast on errors
Testing Jobs Unit tests, integration tests, E2E tests, coverage, security scans, lighthouse Jest/Vitest for unit. Playwright for E2E. Upload coverage to Codecov. Parallel tests Run unit tests first (fast). E2E on preview deploy. 80%+ coverage. Security scan dependencies
Deploy Job Production deploy, staging deploy, preview environments, rollback capability needs: [build, test]. Use secrets for credentials. Conditional on branch Deploy after tests pass. Use environment protection rules. Auto-rollback on failure
Caching Strategy Dependencies, build artifacts, node_modules, .next cache, test cache actions/cache@v4 with key: ${{ runner.os }}-node-${{ hashFiles }} Cache node_modules (2-5 min → 30s). Restore build cache. Use restore-keys fallback
Security & Secrets Encrypted secrets, OIDC tokens, environment secrets, secret scanning, Dependabot Store in GitHub Secrets. Use ${{ secrets.API_KEY }}. Never log secrets Rotate secrets quarterly. Use OIDC instead of tokens. Enable secret scanning. Audit access

Example: Complete CI/CD pipeline

# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20]
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'pnpm'
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Lint
        run: pnpm lint
      
      - name: Type check
        run: pnpm type-check
      
      - name: Unit tests
        run: pnpm test:unit --coverage
      
      - name: Build
        run: pnpm build
        
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/coverage-final.json

  e2e-tests:
    needs: build-and-test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'
      - run: pnpm install
      - run: pnpm playwright install --with-deps
      - run: pnpm test:e2e
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/

  deploy:
    needs: [build-and-test, e2e-tests]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to Vercel
        run: vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
        env:
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

3. Docker Container Frontend Apps

Aspect Implementation Configuration Best Practices
Multi-stage Build Build stage, Production stage, Nginx serving, Minimize image size, Security hardening Stage 1: node:20-alpine build. Stage 2: nginx:alpine-slim copy artifacts. 50-100MB final Use alpine images. Copy only dist/. Remove source maps. Non-root user. Scan vulnerabilities
Nginx Configuration Static file serving, SPA routing, Gzip compression, Cache headers, Security headers nginx.conf: try_files, gzip on, cache-control, add_header. Port 80/8080 Enable gzip (70% reduction). Cache static assets. SPA fallback index.html. HTTPS redirect
Build Optimization Layer caching, .dockerignore, Dependency caching, Parallel builds, Build args Copy package.json first. Install deps. Copy source. Build. Use BuildKit cache mounts Cache npm install layer. .dockerignore node_modules. Use --mount=type=cache. 10x faster
Environment Variables Runtime config, Build-time vars, ARG vs ENV, Config injection, 12-factor app ARG for build. ENV for runtime. Use window.__ENV__ or env.js. No secrets in image Inject at runtime (not build). Use ConfigMaps in K8s. Template env.js file. Never commit secrets
Health Checks Container health, Startup probe, Readiness probe, Liveness probe, Graceful shutdown HEALTHCHECK CMD curl -f http://localhost/ || exit 1. 30s interval Return 200 on /health. Check dependencies. Fail if not ready. K8s probes required
Security Hardening Non-root user, Minimal base image, Vulnerability scanning, No secrets, Read-only FS USER node (1000). RUN chmod. Trivy/Snyk scan. Secrets from vault. COPY --chown Scan images weekly. Update base images. No RUN as root. Mount secrets. Least privilege

Example: Production Dockerfile with multi-stage build

# Dockerfile
# Stage 1: Build
FROM node:20-alpine AS builder

WORKDIR /app

# Copy package files
COPY package*.json pnpm-lock.yaml ./

# Install dependencies with cache mount
RUN --mount=type=cache,target=/root/.npm \
    npm install -g pnpm && \
    pnpm install --frozen-lockfile

# Copy source
COPY . .

# Build application
RUN pnpm build

# Stage 2: Production
FROM nginx:alpine-slim

# Copy nginx config
COPY nginx.conf /etc/nginx/nginx.conf

# Copy built assets
COPY --from=builder /app/dist /usr/share/nginx/html

# Create non-root user
RUN addgroup -g 1000 appuser && \
    adduser -D -u 1000 -G appuser appuser && \
    chown -R appuser:appuser /usr/share/nginx/html && \
    chown -R appuser:appuser /var/cache/nginx

# Switch to non-root
USER appuser

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
    CMD wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1

EXPOSE 8080

CMD ["nginx", "-g", "daemon off;"]

Example: Nginx configuration for SPA

# nginx.conf
events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1000;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
    
    server {
        listen 8080;
        server_name _;
        root /usr/share/nginx/html;
        index index.html;
        
        # Security headers
        add_header X-Frame-Options "DENY" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        
        # Cache static assets
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
        
        # SPA routing - fallback to index.html
        location / {
            try_files $uri $uri/ /index.html;
        }
        
        # API proxy (optional)
        location /api/ {
            proxy_pass http://backend:3000/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

4. CloudFront S3 Static Hosting

Component Configuration Features Best Practices
S3 Bucket Setup Static website hosting, Bucket policy, CORS config, Versioning, Lifecycle rules Host index.html, Public read access, Website endpoint, 99.99% durability Enable versioning. Lifecycle delete old versions. Block public write. Use IAM roles
CloudFront CDN Global edge network, SSL/TLS, Custom domain, Origin access, Cache behavior 450+ edge locations, Sub-50ms latency, DDoS protection, HTTP/2, Brotli compression Use CloudFront OAI. Custom error pages. Cache everything. Invalidate on deploy
Cache Strategy Cache-Control headers, TTL settings, Query string caching, Version/hash filenames Max-age 31536000 for static. No-cache for HTML. ETags for validation Hash filenames for cache-busting. Cache static 1yr. HTML no-cache. Use CloudFront Functions
SSL Certificate ACM certificate, HTTPS redirect, TLS 1.2+, Custom domain, DNS validation Free SSL via ACM, Auto-renewal, SNI support, Modern cipher suites Use us-east-1 for ACM. Enable HTTPS only. HTTP→HTTPS redirect. Enable HSTS
Error Handling Custom error pages, 404 fallback, 403 to index, SPA routing support Return index.html for 404/403, Custom error pages, Status code mapping 404→index.html for SPA. Custom 500 page. Monitor 4xx/5xx rates. Log errors to S3
Security Headers CSP, X-Frame-Options, HSTS, Referrer-Policy, Permissions-Policy CloudFront Functions or Lambda@Edge for headers. WAF for DDoS. Geo-blocking Add security headers via CF Functions. Enable WAF. Block bots. Rate limiting

Example: Deploy script for S3 + CloudFront

#!/bin/bash
# deploy.sh

# Build application
npm run build

# Sync to S3 with cache headers
aws s3 sync dist/ s3://my-app-bucket/ \
  --delete \
  --cache-control "max-age=31536000,public,immutable" \
  --exclude "index.html" \
  --exclude "*.html"

# Upload HTML with no-cache
aws s3 sync dist/ s3://my-app-bucket/ \
  --cache-control "no-cache,no-store,must-revalidate" \
  --exclude "*" \
  --include "*.html"

# Invalidate CloudFront cache
aws cloudfront create-invalidation \
  --distribution-id E1234ABCD5678 \
  --paths "/*"

echo "Deployment complete!"

Example: CloudFront Functions for security headers

// cloudfront-function.js
function handler(event) {
    var response = event.response;
    var headers = response.headers;

    // Security headers
    headers['strict-transport-security'] = { 
        value: 'max-age=31536000; includeSubDomains; preload' 
    };
    headers['x-content-type-options'] = { value: 'nosniff' };
    headers['x-frame-options'] = { value: 'DENY' };
    headers['x-xss-protection'] = { value: '1; mode=block' };
    headers['referrer-policy'] = { value: 'strict-origin-when-cross-origin' };
    headers['content-security-policy'] = { 
        value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" 
    };

    return response;
}

5. Blue-Green Canary Deployment

Strategy Description Implementation Use Cases & Benefits
Blue-Green Deployment Two identical environments. Deploy to green. Switch traffic. Instant rollback Load balancer routes to blue. Deploy green. Test. Switch DNS/LB. Keep blue for rollback Zero downtime. Instant rollback. Test production environment. Database challenge
Canary Deployment Gradual rollout. 5%→25%→50%→100% traffic. Monitor metrics. Rollback on issues Deploy canary. Route 5% traffic. Monitor errors/latency. Increase if healthy. Full rollout Risk mitigation. Early issue detection. Gradual rollout. Metrics-driven
A/B Testing Multiple versions. Split traffic by user attributes. Compare metrics. Data-driven decisions Deploy variants. Route by user ID/cookie. Track conversion. Statistical significance Feature testing. UI experiments. Business metrics. User segmentation
Feature Flags Toggle features runtime. Gradual rollout. Kill switch. No redeployment needed LaunchDarkly, Unleash, Split. Boolean/percentage rollout. User targeting. Override UI Decouple deploy from release. Instant kill switch. User targeting. Beta testing
Rolling Deployment Update servers one-by-one. Always available. Gradual migration. Version coexistence K8s RollingUpdate. Update 25% pods at a time. Health checks. Rollback on failure No downtime. Incremental. Resource efficient. Slower than blue-green
Rollback Strategy Instant traffic switch. Version pinning. Database migrations. State management Keep previous version. DNS/LB switch. Feature flag disable. DB backward compatible Sub-1min rollback. No data loss. Audit trail. Automated rollback on errors

Example: Kubernetes canary deployment with Flagger

# canary.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: frontend-app
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: frontend-app
  service:
    port: 80
  analysis:
    interval: 1m
    threshold: 5
    maxWeight: 50
    stepWeight: 10
    metrics:
    - name: request-success-rate
      thresholdRange:
        min: 99
      interval: 1m
    - name: request-duration
      thresholdRange:
        max: 500
      interval: 1m
  # Traffic routing
  canaryAnalysis:
    # Start with 10% traffic
    # Increase by 10% every minute if healthy
    # Rollback if 5 failures

Example: Feature flag implementation

// featureFlags.ts
import { LaunchDarkly } from '@launchdarkly/node-server-sdk';

const ldClient = LaunchDarkly.init(process.env.LD_SDK_KEY);

export async function checkFeature(
  userId: string, 
  flagKey: string
): Promise<boolean> {
  const user = { key: userId };
  const flagValue = await ldClient.variation(flagKey, user, false);
  return flagValue;
}

// React component usage
function NewFeature() {
  const { flags } = useLDClient();
  
  if (!flags.newCheckoutFlow) {
    return <OldCheckout />;
  }
  
  return <NewCheckout />;
}

// Gradual rollout configuration in LaunchDarkly:
// - 0-5%: Internal users only
// - 5-25%: Beta users
// - 25-50%: Random 50% of users
// - 50-100%: All users
// Rollback: Set to 0% instantly

6. Environment Variables Config Management

Aspect Implementation Tools & Patterns Security & Best Practices
12-Factor Config Separate config from code. Store in environment. Different per deploy. No secrets in repo .env files locally. Platform env vars in prod. Process.env access. Validation at startup Never commit .env. Use .env.example template. Validate required vars. Fail fast if missing
Frontend Env Vars Build-time injection. Runtime config. Public vs private. VITE_*, NEXT_PUBLIC_*, REACT_APP_* Vite: VITE_ prefix. Next: NEXT_PUBLIC_. CRA: REACT_APP_. Expose via import.meta.env Never expose secrets to frontend. Use prefixes for public vars. Runtime config for sensitive
Secrets Management Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, Encrypted at rest Store API keys, DB creds, tokens. Rotate regularly. Access control. Audit logs Never log secrets. Rotate every 90 days. Least privilege access. Use temporary credentials
Multi-Environment dev, staging, production. Different config per env. Promote config through pipeline .env.development, .env.production. Platform env vars. Config service. Feature flags Production parity. Explicit env switching. No dev secrets in prod. Test staging config
Validation & Type Safety Zod/Joi validation. TypeScript env types. Fail at startup. Required vs optional Zod schema validation. @t3-oss/env-nextjs. Env.d.ts types. Runtime validation Validate on app start. Type-safe access. Clear error messages. Document all variables
Config Injection Runtime config. window.__ENV__. Config endpoint. Dynamic without rebuild Serve config.js from server. Template replacement. K8s ConfigMaps. Consul/etcd No rebuild for config changes. Separate config deployment. Versioned config. Rollback support

Example: Environment validation with Zod

// env.ts
import { z } from 'zod';

const envSchema = z.object({
  // Public variables (exposed to frontend)
  VITE_API_URL: z.string().url(),
  VITE_APP_ENV: z.enum(['development', 'staging', 'production']),
  VITE_SENTRY_DSN: z.string().optional(),
  
  // Server-only variables (not exposed)
  DATABASE_URL: z.string().min(1),
  API_SECRET_KEY: z.string().min(32),
  JWT_SECRET: z.string().min(32),
  
  // Optional with defaults
  PORT: z.string().default('3000'),
  LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});

// Validate at startup
const env = envSchema.parse(process.env);

// Type-safe access
export { env };

// Usage
import { env } from './env';
console.log(env.VITE_API_URL); // Type-safe, validated

Example: Runtime config injection for Docker

// public/config.js template
window.__ENV__ = {
  API_URL: '${API_URL}',
  ENVIRONMENT: '${ENVIRONMENT}',
  FEATURE_FLAGS: '${FEATURE_FLAGS}'
};

// entrypoint.sh - Replace at container start
#!/bin/sh
envsubst < /usr/share/nginx/html/config.js.template \
  > /usr/share/nginx/html/config.js
nginx -g 'daemon off;'

// Access in React
const config = (window as any).__ENV__;
const API_URL = config.API_URL || 'http://localhost:3000';

// Kubernetes ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: frontend-config
data:
  API_URL: "https://api.production.com"
  ENVIRONMENT: "production"
  FEATURE_FLAGS: "new-ui,beta-checkout"
Environment Best Practices:
  • Local Development: Use .env files with dotenv. Never commit .env, only .env.example
  • CI/CD: Store secrets in GitHub Secrets, GitLab CI/CD variables, or CircleCI contexts
  • Production: Use platform env vars (Vercel, Netlify) or secrets managers (AWS Secrets Manager)
  • Validation: Validate all env vars at startup. Fail fast with clear errors. Use Zod/Joi
  • Documentation: Maintain .env.example. Document required vs optional. Include in README

Deployment & Delivery Summary

  • Jamstack Platforms: Vercel/Netlify for zero-config. Edge functions for low latency. Preview deploys for testing. Free tier 100GB
  • CI/CD Pipeline: GitHub Actions for automation. Cache dependencies (10x faster). Parallel tests. Deploy after tests pass
  • Docker: Multi-stage builds (50-100MB). Nginx for serving. Non-root user. Layer caching. Security scanning
  • CloudFront + S3: Global CDN. Cache static 1yr. HTML no-cache. CloudFront Functions for headers. $0.085/GB
  • Deployment Strategies: Blue-green for instant rollback. Canary for gradual rollout. Feature flags for toggle. A/B for testing
  • Config Management: 12-factor app. Separate per environment. Zod validation. Never commit secrets. Runtime injection
Production Checklist: Implement CI/CD automation, enable preview deploys, use canary deployments, validate environment variables, add health checks, enable monitoring, and maintain rollback capability. Target <5min deployment time, 99.9% uptime.