// netlify.toml[build] base = "/" publish = "dist" command = "npm run build"[build.environment] NODE_VERSION = "18" NPM_FLAGS = "--legacy-peer-deps"# Redirect rules[[redirects]] from = "/old-url" to = "/new-url" status = 301[[redirects]] from = "/api/*" to = "https://api.example.com/:splat" status = 200[[redirects]] from = "/*" to = "/index.html" status = 200 # SPA fallback# Headers[[headers]] for = "/*" [headers.values] X-Frame-Options = "DENY" X-XSS-Protection = "1; mode=block" X-Content-Type-Options = "nosniff" Referrer-Policy = "strict-origin-when-cross-origin"[[headers]] for = "/static/*" [headers.values] Cache-Control = "public, max-age=31536000, immutable"# Functions (serverless)[functions] directory = "netlify/functions" node_bundler = "esbuild"# Dev server[dev] command = "npm run dev" port = 3000 publish = "dist"# Deploy contexts[context.production] environment = { NODE_ENV = "production" }[context.deploy-preview] environment = { NODE_ENV = "staging" }[context.branch-deploy] environment = { NODE_ENV = "development" }# Form handling (Netlify feature)# In HTML:<form name="contact" method="POST" data-netlify="true"> <input type="text" name="name" /> <input type="email" name="email" /> <button type="submit">Submit</button></form># Deploy via CLInpm install -g netlify-clinetlify loginnetlify initnetlify deploy --prod
Example: Cloudflare Pages deployment
// wrangler.toml (for Pages with Functions)name = "my-app"compatibility_date = "2024-01-01"[build] command = "npm run build" cwd = "." watch_dir = "src"[[build.upload]] format = "service-worker" main = "./functions/[[path]].js"[env.production] [env.production.vars] API_URL = "https://api.example.com"# _redirects file (in public folder)/old-url /new-url 301/api/* https://api.example.com/:splat 200/* /index.html 200# _headers file/* X-Frame-Options: DENY X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff/static/* Cache-Control: public, max-age=31536000, immutable# Cloudflare Pages Function// functions/api/hello.tsexport async function onRequest(context) { const { request, env, params } = context; return new Response(JSON.stringify({ message: 'Hello from Cloudflare Pages', time: new Date().toISOString() }), { headers: { 'Content-Type': 'application/json' } });}# Deploy via CLInpm install -g wranglerwrangler loginwrangler pages publish dist --project-name=my-app# Or use Git integration (automatic)# Connect GitHub repo → automatic deployments
Platform Selection: Vercel for Next.js apps with edge functions. Netlify for static sites with
forms and split testing.
Cloudflare Pages for unlimited bandwidth. All provide automatic HTTPS, CDN, preview deployments, and Git
integration.
2. Docker Container Frontend Apps
Containerize frontend applications with Docker for consistent deployments across environments and orchestration
with Kubernetes.
Security Best Practices: Use multi-stage builds to reduce image size. Run as non-root user.
Scan
images for
vulnerabilities with docker scan. Use .dockerignore to exclude unnecessary files. Pin base image versions.
3. CDN CloudFront Asset Optimization
Distribute static assets globally with CDN for faster load times, reduced latency, and improved user experience
worldwide.
CDN Provider
Key Features
Best For
Pricing Model
CloudFront (AWS)
Global edge, Lambda@Edge
AWS ecosystem integration
Pay per request
Cloudflare
DDoS protection, workers
Security, free tier
Free + paid plans
Fastly
Instant purge, VCL
Real-time apps
Pay as you go
Akamai
Largest network
Enterprise scale
Enterprise pricing
Example: CloudFront distribution setup with Terraform
// workers/optimize-images.jsexport default { async fetch(request, env) { const url = new URL(request.url); // Check if WebP is supported const acceptHeader = request.headers.get('Accept') || ''; const supportsWebP = acceptHeader.includes('image/webp'); // Transform image format at edge if (url.pathname.match(/\.(jpg|png)$/)) { const imageRequest = new Request(request); if (supportsWebP) { // Serve WebP version const webpUrl = url.pathname.replace(/\.(jpg|png)$/, '.webp'); return fetch(new Request(webpUrl, imageRequest)); } } // Add custom headers const response = await fetch(request); const newResponse = new Response(response.body, response); // Cache static assets aggressively if (url.pathname.startsWith('/static/')) { newResponse.headers.set('Cache-Control', 'public, max-age=31536000, immutable'); } // Security headers newResponse.headers.set('X-Content-Type-Options', 'nosniff'); newResponse.headers.set('X-Frame-Options', 'DENY'); return newResponse; }};// wrangler.tomlname = "image-optimizer"main = "workers/optimize-images.js"compatibility_date = "2024-01-01"[env.production]route = "example.com/*"
CDN Best Practices: Use content hashing for immutable assets. Set aggressive cache headers for
static files.
Invalidate cache selectively. Enable compression (Gzip/Brotli). Use HTTP/2 push for critical resources. Monitor
CDN hit ratio.
4. Environment Variables Config
Manage environment-specific configuration securely across development, staging, and production environments.
Approach
Use Case
Security
Complexity
.env Files
Local development
Low (gitignored)
Low
Platform Secrets
Vercel/Netlify secrets
High (encrypted)
Low
AWS Secrets Manager
Production secrets
High (encrypted, rotated)
Medium
HashiCorp Vault
Enterprise secrets
Very High
High
Example: Environment variables setup with validation
// .env.example (commit to git)NEXT_PUBLIC_API_URL=https://api.example.comNEXT_PUBLIC_GA_ID=G-XXXXXXXXXXDATABASE_URL=postgresql://localhost:5432/mydbJWT_SECRET=your-secret-key-hereSTRIPE_SECRET_KEY=sk_test_xxx// .env.local (gitignored - actual values)NEXT_PUBLIC_API_URL=http://localhost:4000NEXT_PUBLIC_GA_ID=G-123456789DATABASE_URL=postgresql://user:pass@localhost:5432/mydb_devJWT_SECRET=super-secret-dev-keySTRIPE_SECRET_KEY=sk_test_actual_key// .env.production (production values - use secrets manager)NEXT_PUBLIC_API_URL=https://api.production.comNEXT_PUBLIC_GA_ID=G-PROD123456DATABASE_URL=@database-url-secretJWT_SECRET=@jwt-secretSTRIPE_SECRET_KEY=@stripe-secret// .gitignore.env*.local.env.production// config/env.ts - Type-safe environment variablesimport { z } from 'zod';const envSchema = z.object({ // Public variables (available in browser) NEXT_PUBLIC_API_URL: z.string().url(), NEXT_PUBLIC_GA_ID: z.string().optional(), // Server-only variables DATABASE_URL: z.string(), JWT_SECRET: z.string().min(32), STRIPE_SECRET_KEY: z.string().startsWith('sk_'), // Environment NODE_ENV: z.enum(['development', 'staging', 'production']).default('development')});// Validate and exportconst _env = envSchema.safeParse(process.env);if (!_env.success) { console.error('❌ Invalid environment variables:', _env.error.format()); throw new Error('Invalid environment variables');}export const env = _env.data;// Usageimport { env } from '@/config/env';console.log(env.NEXT_PUBLIC_API_URL); // Type-safe accessconsole.log(env.JWT_SECRET); // Only available server-side
Security Best Practices: Never commit secrets to git. Use .env.example for documentation.
Rotate
secrets
regularly. Use different secrets per environment. Prefix public variables with NEXT_PUBLIC_ or VITE_. Validate
all
env vars.
5. Blue-Green Canary Deployment
Implement zero-downtime deployment strategies with instant rollback capabilities and gradual traffic shifting.
Strategy
Approach
Risk
Rollback Time
Blue-Green
Switch all traffic instantly
Medium
Instant
Canary
Gradual traffic shift (5%→50%→100%)
Low
Quick
Rolling Update
Replace instances one by one
Low
Minutes
A/B Testing
Split traffic by user segment
Low
N/A (experimental)
Example: Kubernetes Blue-Green deployment
# blue-deployment.yaml (current production)apiVersion: apps/v1kind: Deploymentmetadata: name: frontend-blue labels: app: frontend version: bluespec: replicas: 3 selector: matchLabels: app: frontend version: blue template: metadata: labels: app: frontend version: blue spec: containers: - name: frontend image: myapp/frontend:v1.0.0 ports: - containerPort: 80 resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m"---# green-deployment.yaml (new version)apiVersion: apps/v1kind: Deploymentmetadata: name: frontend-green labels: app: frontend version: greenspec: replicas: 3 selector: matchLabels: app: frontend version: green template: metadata: labels: app: frontend version: green spec: containers: - name: frontend image: myapp/frontend:v2.0.0 # New version ports: - containerPort: 80 resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m"---# service.yamlapiVersion: v1kind: Servicemetadata: name: frontend-servicespec: selector: app: frontend version: blue # Initially pointing to blue ports: - protocol: TCP port: 80 targetPort: 80 type: LoadBalancer# Deployment process:# 1. Deploy green versionkubectl apply -f green-deployment.yaml# 2. Test green version internallykubectl port-forward deployment/frontend-green 8080:80# 3. Switch traffic to green (instant cutover)kubectl patch service frontend-service -p '{"spec":{"selector":{"version":"green"}}}'# 4. Monitor for issueskubectl logs -f deployment/frontend-green# 5. If issues, rollback to blue instantlykubectl patch service frontend-service -p '{"spec":{"selector":{"version":"blue"}}}'# 6. If successful, delete blue deploymentkubectl delete deployment frontend-blue
// Vercel automatic preview deployments// Every PR gets a unique preview URL// .github/workflows/preview.ymlname: Preview Deploymenton: pull_request: branches: [main]jobs: deploy-preview: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Deploy to Vercel uses: amondnet/vercel-action@v20 with: vercel-token: ${{ secrets.VERCEL_TOKEN }} vercel-org-id: ${{ secrets.ORG_ID }} vercel-project-id: ${{ secrets.PROJECT_ID }} scope: ${{ secrets.VERCEL_SCOPE }} - name: Comment PR uses: actions/github-script@v6 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: '🚀 Preview deployed to: https://my-app-pr-${{ github.event.number }}.vercel.app' })// Netlify branch deploys// netlify.toml[context.deploy-preview] command = "npm run build" environment = { NODE_ENV = "staging" }[context.branch-deploy] command = "npm run build"# Each branch gets: https://branch-name--my-app.netlify.app# Each PR gets: https://deploy-preview-123--my-app.netlify.app// Progressive rollout with feature flagsimport { useFeatureFlag } from '@/lib/feature-flags';function NewFeature() { const isEnabled = useFeatureFlag('new-ui-redesign', { rollout: 10 // Start with 10% of users }); if (!isEnabled) { return <OldFeature />; } return <RedesignedFeature />;}// Gradually increase rollout// Day 1: 10%// Day 3: 25%// Day 7: 50%// Day 14: 100%
Deployment Strategy Selection: Blue-Green for instant rollback with no downtime. Canary for
gradual rollout
with monitoring. Rolling update for resource-constrained environments. Always test in staging first.
6. Monitoring Sentry Performance Tracking
Implement comprehensive monitoring and error tracking to detect issues early and maintain application health in
production.