
Ci Cd Architecture
- 140 installs
- 14 repo stars
- Updated March 2, 2026
- oakoss/agent-skills
Helps with ai & agent building tasks during AI-assisted development.
About
ci-cd-architecture is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- ci-cd-architecture
- AI & Agent Building
- AI-coding skill
Ci Cd Architecture by the numbers
- 140 all-time installs (skills.sh)
- +7 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #3,485 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/oakoss/agent-skills --skill ci-cd-architectureAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 140 |
|---|---|
| repo stars | ★ 14 |
| Last updated | March 2, 2026 |
| Repository | oakoss/agent-skills ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
CI/CD & Deployment
Overview
Covers CI/CD pipeline design, deployment platform selection, and production infrastructure. Focuses on GitHub Actions with hardened security (OIDC, permission scoping, action pinning), Bun-first build optimization, and deployment patterns from MVP to enterprise scale.
When to use: Setting up GitHub Actions workflows, choosing deployment targets, configuring OIDC for cloud providers, optimizing CI performance, planning multi-environment pipelines.
When NOT to use: Application-level architecture decisions (use framework-specific skills), Kubernetes cluster management (use dedicated IaC tools), cloud provider console configuration.
Quick Reference
| Need | Solution |
|---|---|
| MVP deploy (< 1K users) | Vercel, Netlify, Railway, Cloudflare Pages |
| Growing product (1K-100K) | AWS Amplify, Cloud Run, Fly.io, Render |
| Enterprise (100K+) | AWS ECS/EKS, GKE, DigitalOcean App Platform |
| Static site | Vercel, Netlify, Cloudflare Pages |
| Full-stack + DB | Railway, Render, AWS Amplify |
| Global low latency | Cloudflare Workers, Vercel Edge, Fly.io |
| Compliance (HIPAA, SOC 2) | AWS, GCP, Azure |
| Cloud auth from CI | OIDC roles (never long-lived keys) |
| Action pinning | Pin to commit SHA, not tag |
| Bun CI caching | ~/.bun/install/cache keyed on lockfile |
| Pipeline security | StepSecurity Harden-Runner for egress control |
| Container builds | Multi-stage Dockerfile: builder + runtime stage |
| Docker layer caching | --cache-from + actions/cache for buildx |
| Multi-platform builds | docker buildx targeting linux/amd64,linux/arm64 |
| Image scanning | Trivy or Snyk in pipeline before push |
| Registry push | GHCR (ghcr.io), ECR, Docker Hub |
| Pipeline stages | build → test → security scan → deploy |
| DORA: deploy frequency | Track deployments per day/week per service |
| DORA: lead time | Commit-to-production time; target < 1 hour |
| DORA: change failure rate | % of deploys causing incidents; target < 5% |
| DORA: MTTR | Mean time to restore; target < 1 hour |
Common Mistakes
| Mistake | Correct Pattern |
|---|---|
| Storing long-lived AWS/GCP/Azure keys as GitHub secrets | Use OIDC roles with id-token: write permission for zero-trust cloud auth |
| Pinning GitHub Actions to tags instead of commit SHAs | Pin third-party actions to full commit SHA to prevent supply chain attacks |
Leaving permissions as default (broad) on workflows | Explicitly scope permissions at the job level; default to contents: read |
| Running full CI on every branch push | Use on.pull_request filters and path-based triggers to avoid wasted compute |
| Over-engineering infrastructure before product-market fit | Start with managed platforms (Vercel, Railway); scale to AWS/GKE only when needed |
| Using outdated action versions (v3 or older) | Use current major versions: checkout@v6, cache@v5, configure-aws-credentials@v5 |
Caching only bun.lockb without considering bun.lock | Bun 1.2+ uses text-based bun.lock; hash whichever lockfile format the project uses |
| Skipping preview deployments for PRs | Every PR should get a preview URL for testing before merge |
Relationship to Other Skills
If thegithub-actionsskill is available, delegate detailed workflow authoring, matrix strategies, and composite actions to it. This skill covers CI/CD architecture and platform selection;github-actionscovers workflow syntax depth.
If the deployment-strategy skill is available, delegate deployment pattern selection (blue-green, canary, rolling) to it. This skill covers platform selection and CI pipeline mechanics.Delegation
- Audit existing CI workflow security and permissions: Use
Exploreagent to scan workflow YAML files for broad permissions, unpinned actions, and exposed secrets - Set up multi-environment deployment pipelines: Use
Taskagent to create dev/staging/prod workflows with environment protection rules - Plan migration from managed platform to containerized infrastructure: Use
Planagent to evaluate current deployment, define migration steps, and select target architecture
References
- GitHub Actions workflows, OIDC, matrix builds, and security hardening
- Deployment patterns: Jamstack, serverless, traditional, microservices
- Platform selection framework, database needs, and cost optimization
- Monitoring, observability tiers, and deployment checklists
- Container builds: multi-stage Dockerfiles, layer caching, buildx, image scanning, and registry push
Container Builds
Multi-Stage Dockerfile
Separate build tooling from the runtime image to keep the final image small and free of dev dependencies.
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ['node', 'dist/index.js']Distroless Runtime (Minimal Attack Surface)
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM gcr.io/distroless/nodejs22-debian12 AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ['dist/index.js']Alpine vs Distroless
| Image base | Size | Shell | Package manager | Use case |
|---|---|---|---|---|
node:22-alpine | ~50 MB | ash | apk | Needs runtime shell tools |
distroless/nodejs | ~30 MB | none | none | Hardened production |
scratch | 0 MB | none | none | Statically linked binaries |
.dockerignore
Always add a .dockerignore to exclude build artifacts and sensitive files.
node_modules
.git
.env*
dist
coverage
*.log
.DS_StoreDocker Layer Caching in CI
Cache with --cache-from (BuildKit)
- name: Build image
run: |
docker build \
--cache-from ghcr.io/${{ github.repository }}:cache \
--build-arg BUILDKIT_INLINE_CACHE=1 \
-t ghcr.io/${{ github.repository }}:${{ github.sha }} \
.Cache with GitHub Actions cache backend (buildx)
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=maxtype=gha uses GitHub Actions cache storage — no registry needed and automatically evicted per cache policy.
Registry cache backend (persistent across runners)
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:cache
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:cache,mode=maxbuildx Multi-Platform Builds
Build a single image manifest supporting both linux/amd64 (x86 servers) and linux/arm64 (Graviton, Apple Silicon).
name: Build multi-platform image
on:
push:
branches: [main]
permissions:
contents: read
packages: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=maxQEMU is needed for cross-compilation on the ubuntu-latest runner. Native arm64 runners skip QEMU but cost more.
Image Scanning
Scan images for CVEs before pushing to production registries.
Trivy (free, runs in CI)
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@0.28.0
with:
image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }}
format: table
exit-code: '1'
severity: CRITICAL,HIGH
ignore-unfixed: trueexit-code: '1' fails the pipeline on critical/high CVEs. ignore-unfixed: true skips vulnerabilities with no available fix.
Trivy filesystem scan (scan before build)
- name: Scan filesystem
uses: aquasecurity/trivy-action@0.28.0
with:
scan-type: fs
scan-ref: .
format: sarif
output: trivy-results.sarif
- name: Upload to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarifSnyk container scan
- name: Scan image with Snyk
uses: snyk/actions/docker@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
image: ghcr.io/${{ github.repository }}:${{ github.sha }}
args: --severity-threshold=highPushing to Registries
GitHub Container Registry (GHCR)
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}GITHUB_TOKEN is sufficient — no separate secret needed for GHCR when pushing from the same repository.
Amazon ECR (with OIDC)
permissions:
id-token: write
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/github-actions-ecr
aws-region: us-east-1
- name: Log in to ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}Docker Hub
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}Use an access token (not password). Store username as a variable (vars.), token as a secret.
Image Tagging Strategy
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=sha,prefix=sha-
type=ref,event=branch
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}docker/metadata-action generates consistent tags from git context. Pass steps.meta.outputs.tags to docker/build-push-action.
Full Pipeline: Build → Test → Scan → Push
name: Container CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
packages: write
security-events: write
jobs:
build-scan-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build image (no push)
uses: docker/build-push-action@v6
with:
context: .
load: true
tags: app:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run unit tests inside container
run: docker run --rm app:${{ github.sha }} pnpm test
- name: Scan for vulnerabilities
uses: aquasecurity/trivy-action@0.28.0
with:
image-ref: app:${{ github.sha }}
exit-code: '1'
severity: CRITICAL,HIGH
ignore-unfixed: true
- name: Log in to GHCR
if: github.ref == 'refs/heads/main'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push to registry
if: github.ref == 'refs/heads/main'
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=ghaPush only on main merges. PRs build and scan without pushing.
Size Optimization Checklist
| Technique | Impact |
|---|---|
| Multi-stage build | Strips build tools from runtime image |
.dockerignore | Excludes node_modules, .git, logs |
| Copy only production deps | pnpm install --prod in runtime stage |
| Use Alpine or distroless base | 50-200 MB smaller than full Debian |
Combine RUN commands | Fewer layers, smaller image |
| Remove package manager cache | apk add --no-cache or rm -rf /var/cache |
RUN apk add --no-cache curl \
&& addgroup -S appgroup \
&& adduser -S appuser -G appgroup
USER appuserRun as a non-root user — required for CIS benchmarks and most production security policies.
Deployment Patterns
Jamstack (Static + API)
Frontend (Vercel/Netlify) -> API (Railway/Render) -> Database (Supabase/Neon)Characteristics: Static frontend served from CDN, API calls to separate backend, database hosted independently.
Strengths: Fast global delivery, cheap at low scale, scales frontend independently, strong caching story.
Weaknesses: Not ideal for real-time or server-heavy apps, API latency from separate services, more moving parts than monolith.
Best for: Marketing sites, blogs, documentation, e-commerce storefronts, dashboards with moderate data requirements.
Serverless
Frontend (Vercel/Cloudflare Pages) -> Edge Functions -> Serverless DB (Neon/PlanetScale)Characteristics: Zero server management, functions execute on demand, pay-per-invocation pricing.
Strengths: Zero idle cost, automatic scaling, no infrastructure management, global edge execution.
Weaknesses: Cold start latency (mitigated by edge runtimes), vendor lock-in risk, limited execution time, debugging complexity.
Best for: APIs with variable traffic, webhook handlers, scheduled jobs, applications with unpredictable load patterns.
Traditional Full-Stack
Railway/Render: Node.js API + PostgreSQL + RedisCharacteristics: Application server, database, and cache co-located on a single platform. Persistent processes.
Strengths: Simple mental model, everything in one place, persistent connections (WebSockets, long-polling), predictable pricing.
Weaknesses: Single point of failure, vertical scaling limits, platform coupling.
Best for: MVPs, internal tools, applications requiring WebSockets, projects where simplicity outweighs scale requirements.
Microservices
Frontend (Vercel) -> Service 1 (Cloud Run) -> Database
-> Service 2 (Cloud Run) -> Queue
-> Service 3 (Cloud Run) -> CacheCharacteristics: Independent services with separate deployments, scaling, and data stores. Service-to-service communication via HTTP/gRPC or message queues.
Strengths: Independent scaling, fault isolation, technology flexibility per service, team autonomy.
Weaknesses: Higher complexity, distributed system challenges (consistency, latency, debugging), operational overhead.
Best for: Large teams, high-scale applications, systems requiring independent scaling per component, organizations with strong DevOps practices.
Release Strategies
Rolling Deploy
Gradually replaces old instances with new ones. Zero downtime but no instant rollback. Suitable for most applications.
Blue-Green Deployment
Maintains two identical environments. Traffic switches from blue (current) to green (new) atomically. Instant rollback by switching back. Requires double infrastructure during deployment.
Load Balancer
├── Blue (current, serving traffic)
└── Green (new, idle until switch)Canary Release
Routes a small percentage of traffic to the new version. Monitors error rates and performance. Gradually increases traffic if metrics are healthy. Rolls back immediately if problems detected.
Load Balancer
├── 95% -> Stable version
└── 5% -> Canary version (monitored)Feature Flags
Decouples deployment from release. Code ships to production but features activate based on flag configuration. Enables gradual rollout, A/B testing, and instant kill switches.
Environment Strategy
Three-Environment Model
| Environment | Purpose | Deploy Trigger |
|---|---|---|
| Development | Integration testing, feature preview | Push to feature branch |
| Staging | Pre-production validation, QA | Merge to staging branch or manual |
| Production | Live users | Merge to main with approval |
Environment Protection Rules
Configure environment protection in the deployment platform or CI system:
- Required reviewers for production deploys
- Wait timers between staging and production
- Branch restrictions (only main can deploy to production)
- Deployment concurrency limits to prevent overlapping deploys
Rollback Strategy
Every production deployment must have a rollback plan defined before deploy.
Managed platforms (Vercel, Netlify, Railway): Use built-in instant rollback to previous deployment.
Container-based (ECS, Cloud Run, Kubernetes): Redeploy previous container image tag.
Database migrations: Write forward-compatible migrations that work with both old and new application versions. Avoid destructive migrations (dropping columns) until the old version is fully decommissioned.
Security in Deployments
Must-haves:
- HTTPS everywhere (automatic on most managed platforms)
- Environment variables for secrets (never commit to repository)
- Database encryption at rest
- Regular dependency updates (automated with Dependabot or Renovate)
- Rate limiting on public APIs
Recommended:
- Security headers (CSP, HSTS, X-Frame-Options)
- DDoS protection (Cloudflare, AWS Shield)
- Automated vulnerability scanning in CI pipeline
- Audit logs for sensitive operations
- Backup and disaster recovery plan with tested restore procedures
GitHub Actions
Hardened Production Workflow
A production-ready workflow with OIDC authentication, Bun caching, and strict permissions.
name: Deploy to Production
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache Bun Dependencies
uses: actions/cache@v5
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock', '**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::1234567890:role/github-actions-deploy
aws-region: us-east-1
- name: Build & Deploy
run: bun run build && bun run deployOIDC Cloud Authentication
Long-lived AWS/Azure/GCP keys must not be used in production pipelines. OIDC provides short-lived, dynamically generated tokens.
How OIDC Works
1. Workflow requests a JWT from GitHub's OIDC provider 2. Cloud provider validates the token against a trust policy 3. Cloud provider issues a short-lived access token (typically 1 hour) 4. Token expires automatically after the job completes
AWS OIDC Setup
Required components in AWS:
- An OIDC identity provider pointing to
https://token.actions.githubusercontent.com - An IAM role with a trust policy scoped to the repository
- The audience set to
sts.amazonaws.com
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: us-east-1
role-session-name: GitHubActionsSessionThe IAM trust policy must include a sub condition to restrict which repositories and branches can assume the role. Without this condition, any GitHub repository could potentially assume the role.
Azure OIDC Setup
Azure uses workload identity federation. Configure a federated credential on an Azure AD app registration with:
- Issuer:
https://token.actions.githubusercontent.com - Subject: scoped to your repository and branch
- Audience:
api://AzureADTokenExchange
GCP OIDC Setup
GCP uses Workload Identity Federation. Create a Workload Identity Pool and Provider, then grant the pool access to a service account. Use google-github-actions/auth action with workload_identity_provider and service_account parameters.
Permission Scoping
Explicitly define permissions at the job level. Never rely on defaults, which are overly broad.
permissions:
contents: read
id-token: write
# Only add write permissions where strictly necessaryCommon permission combinations:
| Use Case | Permissions Needed |
|---|---|
| Read-only checkout | contents: read |
| OIDC cloud deploy | id-token: write, contents: read |
| PR comment | pull-requests: write, contents: read |
| Package publish | packages: write, contents: read |
Bun CI Optimization
Caching Strategy
Bun stores downloaded packages in a global cache at ~/.bun/install/cache. Bun 1.2+ introduced a text-based bun.lock format alongside the legacy binary bun.lockb. Hash whichever lockfile format the project uses.
- name: Cache Bun Dependencies
uses: actions/cache@v5
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock', '**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-Performance Tips
- Use
bun install --frozen-lockfilefor deterministic installs - Use
bun testfor sub-second unit and integration test execution - Use
bun runinstead ofnpxfor script execution
Matrix Builds
Run tests across multiple runtime versions in parallel.
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20, 22, 24]
steps:
- uses: actions/checkout@v6
- name: Run Tests
run: bun testMulti-Stage Pipeline
Separate test and deploy into distinct jobs with dependencies.
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun test
- run: bun run lint
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Deploy
run: bun run deployEnterprise Pipeline Stages
Build -> Test -> Security Scan -> Stage Deploy -> Integration Tests -> Prod DeployFeatures at scale: multi-environment (dev/staging/prod), blue-green deployments, canary releases, automated rollbacks, SAST/DAST scanning.
Security Hardening
Action Pinning
Pin third-party actions to a full commit SHA, not a tag or branch. Tags can be moved by maintainers (or attackers), but commit SHAs are immutable.
# Vulnerable — tag can be repointed
- uses: some-org/some-action@v1
# Secure — immutable reference
- uses: some-org/some-action@a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2Egress Control with StepSecurity
StepSecurity Harden-Runner monitors and optionally blocks outbound network traffic from GitHub Actions runners. It detects unauthorized data exfiltration and supply chain attacks at the DNS, HTTPS, and network layers.
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: auditStart with audit mode to build a baseline, then switch to block mode with an explicit allowlist of domains.
Ephemeral Runners
For self-hosted runners, use just-in-time (JIT) runners that are destroyed after a single job execution. This prevents persistent state from leaking between jobs or being compromised.
Troubleshooting
Workflow YAML errors: Use act or dry-run commits to verify syntax and job dependencies before merging.
OIDC failures: Verify the trust relationship configuration in the cloud provider's IAM. Confirm id-token: write is set at the job level, not just at the workflow level if jobs override permissions.
Cache misses: Check that cache keys include the correct lockfile hash. Verify the cache path matches the package manager's install directory. Bun 1.2+ projects use bun.lock (text) instead of bun.lockb (binary).
Slow pipelines: Cache dependencies, use Bun for faster installs and test execution, parallelize independent jobs with matrix builds.
Monitoring and Deployment Checklists
Observability Tiers
Choose a monitoring stack based on the application's scale and budget.
Basic Tier ($0-30/month)
Suitable for MVPs and small production apps.
| Category | Tools |
|---|---|
| Error tracking | Sentry (free tier: 5K errors/month) |
| Uptime monitoring | UptimeRobot or BetterUptime (free tier) |
| Logging | Platform-provided logs (Vercel, Railway, Render) |
| Performance | Vercel Analytics, Cloudflare Web Analytics (free) |
| Alerting | Sentry alerts, UptimeRobot notifications |
Key metrics to track: error rate, uptime percentage, response time (p50/p95), deployment success rate.
Enhanced Tier ($30-200/month)
Suitable for growing products with paying users.
| Category | Tools |
|---|---|
| APM | New Relic or Datadog APM (application traces) |
| Logging | LogTail (Betterstack), Axiom, or Datadog Logs |
| Error tracking | Sentry with performance monitoring |
| Uptime | BetterUptime with status pages |
| Alerting | PagerDuty or Opsgenie for on-call rotation |
Additional metrics: database query latency, cache hit rate, API endpoint latency by route, queue depth, memory/CPU utilization.
Enterprise Tier ($300-2000+/month)
Suitable for high-scale applications with SLA requirements.
| Category | Tools |
|---|---|
| Full-stack observability | Datadog, New Relic, or Grafana Cloud |
| Distributed tracing | OpenTelemetry with Jaeger or Datadog APM |
| Log aggregation | Datadog Logs, Elastic/OpenSearch, Grafana Loki |
| Metrics | Prometheus + Grafana or Datadog Metrics |
| Alerting | PagerDuty with escalation policies |
| Status pages | Statuspage.io or BetterUptime |
Additional capabilities: distributed tracing across services, custom dashboards, SLO/SLI tracking, cost attribution per service, anomaly detection.
Alerting Strategy
Alert Severity Levels
| Level | Response Time | Examples |
|---|---|---|
| Critical (P0) | Immediate (< 5 min) | Site down, data loss, security breach |
| High (P1) | < 30 min | Error rate spike, payment failures |
| Medium (P2) | < 4 hours | Elevated latency, degraded performance |
| Low (P3) | Next business day | Non-critical warnings, capacity planning |
Alert Best Practices
- Alert on symptoms (error rate, latency), not causes (CPU usage)
- Set meaningful thresholds based on baseline data, not arbitrary numbers
- Include runbook links in alert notifications
- Avoid alert fatigue: fewer, actionable alerts are better than many noisy ones
- Use separate notification channels for different severity levels
Deployment Checklists
Pre-Launch Checklist
Infrastructure:
- Environment variables configured for all environments
- Database migrations tested against production-like data
- SSL/HTTPS enabled and certificates valid
- Custom domain connected with proper DNS records
- CDN configured for static assets
Application:
- Error monitoring configured and verified (trigger a test error)
- Logging captures request context (request ID, user ID)
- Health check endpoint returns service status
- Rate limiting configured on public endpoints
- CORS settings restrict to known origins
Security:
- Secrets stored in platform secret management (not in code)
- Database credentials rotated from development defaults
- Security headers configured (CSP, HSTS, X-Frame-Options)
- Dependency audit shows no critical vulnerabilities
- Authentication and authorization flows tested
Operations:
- Backup strategy defined and tested (database, file storage)
- Rollback procedure documented and tested
- On-call rotation established (for production apps with SLAs)
- Runbooks created for common failure scenarios
Launch Day Checklist
- [ ] Deploy to production using standard pipeline
- [ ] Verify all pages/routes load correctly
- [ ] Test critical user flows end-to-end (signup, login, core actions)
- [ ] Check error monitoring dashboard for new errors
- [ ] Verify response times are within acceptable range
- [ ] Confirm analytics/tracking events fire correctly
- [ ] Test from multiple geographic regions if applicable
- [ ] Rollback plan ready and tested
Post-Launch Checklist (First 48 Hours)
- [ ] Monitor error rates and investigate any new error patterns
- [ ] Review response time trends (p50, p95, p99)
- [ ] Check database query performance for slow queries
- [ ] Verify analytics data is collecting accurately
- [ ] Review infrastructure costs against projections
- [ ] Document any issues encountered and resolutions
- [ ] Plan capacity scaling strategy based on observed load
- [ ] Schedule regular review cadence (weekly for first month)
Structured Logging
Use structured logging (JSON format) for machine-parseable logs that integrate with log aggregation tools.
Key fields to include in every log entry:
| Field | Purpose |
|---|---|
timestamp | When the event occurred (ISO 8601) |
level | Severity: debug, info, warn, error |
message | Human-readable description |
requestId | Correlation ID for request tracing |
service | Service name in microservices |
duration | Operation duration in milliseconds |
error | Error message and stack trace (on errors) |
SLO/SLI Framework
Define Service Level Objectives (SLOs) based on Service Level Indicators (SLIs) to measure reliability.
| SLI | Measurement | Typical SLO |
|---|---|---|
| Availability | Successful requests / total requests | 99.9% (8.7 hours downtime/year) |
| Latency (p50) | Median response time | < 200ms |
| Latency (p95) | 95th percentile response time | < 1s |
| Error rate | 5xx responses / total responses | < 0.1% |
| Deployment success | Successful deploys / total deploys | > 95% |
Track error budget (100% - SLO) to balance reliability investment against feature velocity.
Platform Selection
Decision Framework
By Application Type
| App Type | Recommended Platforms |
|---|---|
| Static site | Vercel, Netlify, Cloudflare Pages |
| React/Vue SPA | Vercel, Netlify, Cloudflare Pages |
| Node.js API | Railway, Render, Fly.io, AWS Amplify |
| Python API | Railway, Render, Fly.io, Cloud Run |
| Go/Rust API | Fly.io, Railway, Cloud Run |
| Full-stack + DB | Railway, Render, AWS Amplify |
| Microservices | Fly.io, Cloud Run, AWS ECS |
| Edge-first | Cloudflare Workers, Vercel Edge Functions |
By Scale
| Scale | Platforms | Reasoning |
|---|---|---|
| MVP (< 1K users) | Vercel, Netlify, Railway, Cloudflare Pages | Free tiers, minimal config, fast iteration |
| Growth (1K-100K) | AWS Amplify, Cloud Run, Fly.io, Render | More control, better pricing at scale |
| Enterprise (100K+) | AWS ECS/EKS, GKE, DigitalOcean App Platform | Full control, compliance, custom networking |
By Database Needs
| Need | Options |
|---|---|
| None | Vercel, Netlify, Cloudflare Pages |
| PostgreSQL/MySQL | Railway, Render, AWS RDS, Supabase, Neon |
| Redis/caching | Railway, Render, AWS ElastiCache, Upstash |
| MongoDB | MongoDB Atlas, Railway, AWS DocumentDB |
| Serverless SQL | Neon, PlanetScale, Supabase |
| Global distributed | CockroachDB, Turso (libSQL), Neon (read replicas) |
By Geographic Distribution
Single region: Any platform works. Choose the region closest to the majority of users.
Multi-region: Fly.io (built-in multi-region), Cloudflare Workers (global edge by default), Vercel Edge Functions, AWS multi-region with Route 53.
Global low latency: Cloudflare Workers for compute at the edge, combined with a globally distributed database (Turso, Neon read replicas, or CockroachDB).
By Special Requirements
| Requirement | Platforms |
|---|---|
| Compliance (HIPAA, SOC 2, GDPR) | AWS, GCP, Azure |
| Long-running jobs (> 15 min) | Railway, Render Background Workers, AWS ECS |
| WebSockets/real-time | Railway, Render, Fly.io, AWS ECS |
| High compute (video, ML) | AWS ECS/EKS, Cloud Run, dedicated GPU instances |
| Air-gapped/on-premises | Self-hosted Kubernetes, Docker Compose |
Cost Optimization
Free Tier Strategy ($0-5/month for MVP)
| Platform | Free Tier Highlights |
|---|---|
| Vercel | Free for personal projects, serverless functions included |
| Cloudflare Pages | Unlimited bandwidth, 500 builds/month |
| Supabase | 500 MB database, 50K API requests/day |
| Railway | $5 credit/month |
| Neon | 0.5 GB storage, autoscaling to zero |
| Render | Free static sites, 750 hours/month for services |
Production Cost Optimization
Caching: Use Redis or CDN caching aggressively to reduce compute and database load. Cloudflare offers unlimited bandwidth on free tier for cached assets.
Image optimization: Use framework-level image optimization (Next.js Image, Nuxt Image) or services like Cloudinary to reduce bandwidth costs.
Database connection pooling: Use PgBouncer or built-in pooling (Supabase, Neon) to reduce connection overhead and enable serverless-friendly database access.
Right-sizing: Monitor actual resource usage and scale down over-provisioned instances. Most managed platforms provide usage dashboards.
Spot/preemptible instances: Use for non-critical workloads (CI runners, batch processing, staging environments) at 60-90% discount.
Reserved capacity: For predictable production workloads, reserved instances (AWS) or committed use contracts (GCP) offer significant savings.
Platform Comparison Notes
Vercel
Primary strength is frontend deployment with integrated serverless functions. Native support for Next.js, Nuxt, SvelteKit, and other frameworks. Edge Functions run on Cloudflare's network. Generous free tier for personal projects. Costs can increase quickly at scale with serverless function invocations.
Cloudflare Workers/Pages
Edge-first compute with global distribution by default. V8 isolate model provides fast cold starts (sub-millisecond). Pages for static sites and Workers for compute. D1 (SQLite at the edge) and KV for key-value storage. Strong free tier with unlimited bandwidth.
Railway
Developer-friendly platform with one-click deploys, built-in databases (PostgreSQL, MySQL, Redis, MongoDB), and simple pricing. Good for full-stack applications. Supports Docker containers. Pricing is usage-based with a $5/month credit on the free tier.
Fly.io
Built for multi-region deployment. Runs Docker containers on Firecracker microVMs. Good for applications requiring low latency globally. Built-in support for persistent volumes. Pricing based on VM size and region count.
Render
Similar to Railway with managed databases and automatic deploys from Git. Free static site hosting. Background workers for long-running jobs. Straightforward pricing with clear tiers. Good documentation and onboarding experience.
AWS/GCP/Azure
Full control over infrastructure. Required for compliance-heavy workloads (HIPAA, SOC 2, FedRAMP). Higher operational complexity. Best suited for teams with dedicated DevOps/platform engineering. Cost optimization requires active management.