Deployment & DevOps for MVPs
Purpose
This recipe deploys a full-stack MVP to production with CI/CD pipelines, environment variable management, error tracking, and uptime monitoring — covering five platforms (Vercel, Railway, Fly.io, AWS Amplify, Render) with platform-specific setup instructions, cost benchmarks, and monitoring integration. The output is a live application with automated deployments on every Git push, proper secret management, error alerting, and uptime monitoring. [src1]
Prerequisites
- Application codebase in Git — pushed to GitHub or GitLab with a working local development setup
- Environment variables documented — list of all API keys, database URLs, and secrets needed at runtime
- Deployment platform account — free account at Vercel, Railway, Fly.io, AWS Amplify, or Render
- Sentry account (recommended) — free at sentry.io for error tracking (5K errors/mo free)
- Node.js 18+ or your runtime installed locally for CLI-based deployments
- Custom domain (optional) — registered at Cloudflare, Namecheap, or Porkbun ($10-15/yr)
Constraints
- Vercel Hobby plan is non-commercial only. Any revenue-generating MVP requires Pro at $20/user/mo. [src1]
- Railway charges from first minute of usage — no free tier since 2024. Hobby: $5/mo base + $5 credit. [src2]
- Fly.io has no general free tier for new orgs. Budget minimum ~$2-5/mo for a basic app. [src3]
- AWS Amplify free tier: 5 GB stored, 1 GB served, 1000 build minutes/mo. New accounts get up to $200 in credits. [src4]
- Environment secrets must use platform-native secret management (not .env files committed to Git).
- Database connections from serverless functions require connection pooling to avoid exhausting connection limits.
Tool Selection Decision
Which path?
├── Frontend-only MVP (Next.js, Astro, React SPA)
│ ├── budget = free → PATH A: Vercel Hobby (non-commercial)
│ └── budget > $0 → PATH B: Vercel Pro ($20/mo)
├── Full-stack MVP (frontend + API + database)
│ ├── budget < $10/mo → PATH C: Railway Hobby ($5/mo + usage)
│ ├── budget $10-50/mo → PATH D: Railway Pro ($20/mo) or Render ($7-25/mo)
│ └── budget > $50/mo → PATH E: Fly.io or AWS Amplify
├── API/backend only (no frontend)
│ ├── budget < $10/mo → PATH C: Railway Hobby
│ └── budget > $10/mo → PATH D: Railway Pro or Fly.io
└── Already in AWS ecosystem
└── PATH F: AWS Amplify (leverage existing credits/services)
| Path | Tools | Cost/mo | CI/CD | Best For |
|---|---|---|---|---|
| A: Vercel Hobby | Vercel + Supabase | $0 | Git push auto-deploy | Non-commercial frontend MVPs |
| B: Vercel Pro | Vercel + Supabase/Neon | $20+ | Git push + preview deploys | Commercial Next.js MVPs |
| C: Railway Hobby | Railway (app + DB) | $5-15 | Git push auto-deploy | Side projects, early MVPs |
| D: Railway Pro / Render | Railway or Render | $20-50 | Git push + staging envs | Production MVPs with databases |
| E: Fly.io | Fly.io + managed DB | $20-80 | flyctl deploy + GH Actions | Global low-latency apps |
| F: AWS Amplify | Amplify + RDS/DynamoDB | $0-50 (credits) | Amplify CI/CD pipeline | AWS-centric teams |
Execution Flow
Step 1: Connect Repository and Initial Deploy
Duration: 10-15 minutes · Tool: Deployment platform dashboard or CLI
Connect your Git repository to the deployment platform. Each platform auto-detects frameworks and configures build settings.
Vercel (frontend or Next.js full-stack):
# Dashboard: New Project → Import Git Repository → select repo
# CLI alternative:
npm i -g vercel
cd your-mvp-project
vercel --prod
Railway (full-stack with database):
# Dashboard: New Project → Deploy from GitHub repo
# CLI alternative:
npm i -g @railway/cli
railway login
railway init
railway up
# Add database:
railway add --database postgres
# Connection string auto-injected as DATABASE_URL
Fly.io (global edge deployment):
curl -L https://fly.io/install.sh | sh
fly auth login
fly launch # Follow prompts
fly deploy
# Add PostgreSQL:
fly postgres create --name your-app-db
fly postgres attach your-app-db
Verify: Application loads at the platform-provided subdomain (e.g., your-app.vercel.app, your-app.up.railway.app, your-app.fly.dev). [src1] [src2] · If failed: Check build logs. Common causes: missing build command, wrong output directory, Node.js version mismatch.
Step 2: Configure Environment Variables
Duration: 5-10 minutes · Tool: Platform dashboard or CLI
Store all secrets as platform environment variables. Never commit secrets to Git.
# Vercel
vercel env add DATABASE_URL production
vercel env pull .env.local # For local dev
# Railway
railway variables set DATABASE_URL="postgresql://..."
# Fly.io (encrypted, values hidden after setting)
fly secrets set DATABASE_URL="postgresql://..."
# AWS Amplify: App settings → Environment variables
Verify: Application starts with all env vars loaded. Check logs for "undefined" errors. · If failed: Variable names are case-sensitive. Redeploy after adding variables.
Step 3: Set Up CI/CD Pipeline
Duration: 10-15 minutes · Tool: Platform settings + GitHub Actions
All platforms include auto-deploy on push. Add testing and quality gates with GitHub Actions.
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
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
Vercel creates preview deployments automatically for every PR. Railway and Render support staging environments via branch-based deployments.
Verify: Push a commit — CI tests run, preview deployment created, merge to main triggers production deploy. [src1] [src5] · If failed: Check GitHub Actions logs. Verify platform webhook is connected.
Step 4: Add Monitoring and Error Tracking
Duration: 10-15 minutes · Tool: Sentry + BetterStack/UptimeRobot
# Install Sentry SDK
npm install @sentry/node @sentry/profiling-node
# For Next.js (wizard auto-configures):
npx @sentry/wizard@latest -i nextjs
Add a health check endpoint at /api/health that verifies database connectivity and returns JSON status.
Set up uptime monitoring: BetterStack (free: 10 monitors, 3-min intervals) or UptimeRobot (free: 50 monitors, 5-min intervals).
Verify: Trigger a test error in Sentry — appears in dashboard within 30 seconds. Uptime monitor shows "UP". · If failed: Check Sentry DSN env var. Verify monitor URL is externally accessible.
Step 5: Configure Custom Domain and SSL
Duration: 5-15 minutes · Tool: Platform dashboard + DNS registrar
# Vercel: vercel domains add yourdomain.com
# Railway: Dashboard → Settings → Domains → Add
# Fly.io: fly certs create yourdomain.com
# Render: Dashboard → Settings → Custom Domains
# DNS records at registrar:
# A @ [platform IP]
# CNAME www [platform target]
Verify: https://yourdomain.com loads with valid SSL. HTTP redirects to HTTPS. · If failed: DNS propagation takes up to 48 hours. Check with dnschecker.org.
Step 6: Set Up Log Aggregation (Optional)
Duration: 10 minutes · Tool: Platform-native logs or external service
All platforms provide built-in log viewers. For advanced needs, configure log drains to Datadog, Axiom, or BetterStack.
# Vercel: vercel integrations add datadog
# Railway: Dashboard → Service → Logs (built-in)
# Fly.io: fly logs (or fly logs --json for parsing)
Verify: Generate requests and confirm log entries appear within 60 seconds. · If failed: Ensure app outputs to stdout/stderr, not file-based logging.
Output Schema
{
"output_type": "deployed_mvp_infrastructure",
"format": "live URL + CI/CD pipeline + monitoring",
"columns": [
{"name": "production_url", "type": "string", "description": "Custom domain or platform subdomain", "required": true},
{"name": "platform", "type": "string", "description": "Hosting platform used", "required": true},
{"name": "cicd_status", "type": "string", "description": "CI/CD pipeline status", "required": true},
{"name": "preview_url_pattern", "type": "string", "description": "URL pattern for preview deployments", "required": false},
{"name": "sentry_dsn", "type": "string", "description": "Sentry DSN for error tracking", "required": false},
{"name": "uptime_monitor_url", "type": "string", "description": "Uptime monitoring dashboard URL", "required": false},
{"name": "monthly_cost", "type": "number", "description": "Monthly infrastructure cost in USD", "required": true},
{"name": "ssl_status", "type": "string", "description": "SSL certificate status", "required": true}
],
"expected_row_count": "1",
"sort_order": "N/A",
"deduplication_key": "production_url"
}
Quality Benchmarks
| Quality Metric | Minimum Acceptable | Good | Excellent |
|---|---|---|---|
| Deploy time (push to live) | < 10 minutes | < 3 minutes | < 1 minute |
| Preview deployments | None | Per PR | Per PR with seeded test data |
| Error tracking | None | Sentry captures errors | Sentry + performance monitoring |
| Uptime monitoring | None | 5-min check interval | 1-min check + status page |
| SSL certificate | Valid, no warnings | A rating on ssllabs.com | A+ rating |
| Health check endpoint | None | Returns 200 OK | Checks DB + external deps |
| Rollback capability | Redeploy old commit | 1-click rollback | Auto-rollback on health failure |
If below minimum: Focus on CI/CD pipeline first, then add monitoring. A working deploy pipeline with tests is more valuable than monitoring a broken process.
Error Handling
| Error | Likely Cause | Recovery Action |
|---|---|---|
| "Module not found" build failure | Missing dependency in package.json | Run npm install {module}, commit lockfile, redeploy |
| Node.js version mismatch | Platform default differs from local | Add "engines": {"node": ">=20"} to package.json |
| Deploy timeout | App fails to start or build too long | Check for missing env vars, increase timeout, verify start command |
| 502 Bad Gateway | App crashed on startup | Check runtime logs — usually missing env vars or failed DB connection |
| Database connection refused | Wrong connection string or firewall | Verify DATABASE_URL, check platform IP allowlists, enable connection pooling |
| "Too many connections" | Serverless functions opening new connections per request | Implement connection pooling: Supabase pooler, PgBouncer, or Prisma Accelerate |
| Rate limit 429 | Platform or API limit exceeded | Add caching layer, implement throttling, or upgrade plan |
Cost Breakdown
| Component | Free Tier | Startup ($20-50/mo) | Growth ($50-200/mo) |
|---|---|---|---|
| Vercel hosting | Hobby: $0 (non-commercial) | Pro: $20/user/mo | Pro + usage overage |
| Railway hosting | N/A (no free tier) | Hobby: $5 + usage (~$10-20) | Pro: $20 + usage (~$30-80) |
| Fly.io hosting | N/A (no free tier) | ~$5-15/mo (shared CPU) | ~$20-60/mo (dedicated CPU) |
| AWS Amplify | Free tier ($200 credit) | ~$5-20/mo after credits | ~$20-80/mo |
| Render hosting | Free: 750 hrs/mo | Starter: $7/service | Standard: $25/service |
| Managed database | Supabase/Neon free | Supabase Pro: $25/mo | Railway PG: $10-30/mo |
| Error tracking | Sentry free: 5K errors | Sentry Team: $26/mo | Sentry Business: $80/mo |
| Uptime monitoring | UptimeRobot free | BetterStack: $10/mo | Checkly: $30/mo |
| Total | $0 | $20-60/mo | $80-250/mo |
Anti-Patterns
Wrong: Hardcoding secrets in source code
Committing API keys, database URLs, or secrets directly in source code. Even private repos can leak — credentials in Git history persist forever even after file deletion. [src1]
Correct: Use platform-native secret management
Store all secrets as platform environment variables. Use .env.local for development only with .gitignore protection. Audit with git log --all -S "sk_live".
Wrong: No health checks or monitoring on production
Deploying an MVP and only discovering downtime when users complain. Without monitoring, silent failures go undetected for hours. [src6]
Correct: Health check endpoint + uptime monitor from day one
Add /api/health that checks database connectivity. Configure UptimeRobot or BetterStack (both free) to ping every 5 minutes with Slack/email alerts.
Wrong: Using same database for dev and production
A misconfigured migration or accidental deletion in development destroys production data.
Correct: Separate databases per environment
Use separate database instances for dev, staging, and production. Railway and Render auto-create per-environment databases.
When This Matters
Use this recipe when the agent needs to take a working MVP codebase from local development to a production deployment with CI/CD, environment management, and monitoring. Requires the application code to exist and work locally. This recipe handles infrastructure, not application development.