Module 10: Hosting & Deployment
Deploy your SaaS reliably and cost-effectively.
Platform Comparison
| Platform | Best For | Pricing | Cold Start |
|---|---|---|---|
| Vercel | Next.js apps | Free tier, then usage | Fast |
| Railway | Full-stack + DB | $5/mo + usage | Medium |
| Fly.io | Global edge, containers | Pay per use | Fast |
| AWS/GCP | Enterprise, custom needs | Complex | Varies |
Vercel (Recommended for Next.js)
Deploy from Git
- Push code to GitHub
- Import project at vercel.com
- Configure environment variables
- Deploy
vercel.json Configuration
json
{
"framework": "nextjs",
"regions": ["iad1"],
"env": {
"DATABASE_URL": "@database-url"
},
"headers": [
{
"source": "/api/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "no-store" }
]
}
]
}Environment Variables
bash
# Set via CLI
vercel env add DATABASE_URL production
# Or in dashboard: Settings → Environment Variables
# Access in code
const dbUrl = process.env.DATABASE_URLPreview Deployments
Every PR gets a preview URL:
https://my-app-git-feature-branch-username.vercel.appCustom Domain
- Add domain in Vercel dashboard
- Update DNS records:
- A record:
76.76.21.21 - CNAME:
cname.vercel-dns.com
- A record:
Railway
Good for apps needing persistent services (databases, Redis).
Deploy
bash
# Install CLI
npm install -g @railway/cli
# Login
railway login
# Init project
railway init
# Deploy
railway upDatabase Setup
bash
# Add PostgreSQL
railway add
# Get connection string
railway variables
# Use in .env
DATABASE_URL=postgresql://...railway.json
json
{
"build": {
"builder": "nixpacks"
},
"deploy": {
"startCommand": "npm start",
"healthcheckPath": "/api/health"
}
}Docker Deployment
Dockerfile
dockerfile
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]next.config.js for Docker
javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
}
module.exports = nextConfigCI/CD with GitHub Actions
yaml
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run test
- run: npm run build
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'Database Migrations in CI
yaml
# In deploy job
- name: Run migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}Health Checks
typescript
// app/api/health/route.ts
import { db } from '@/lib/db'
export async function GET() {
try {
// Check database
await db.$queryRaw`SELECT 1`
return Response.json({
status: 'healthy',
timestamp: new Date().toISOString(),
})
} catch (error) {
return Response.json(
{ status: 'unhealthy', error: 'Database connection failed' },
{ status: 503 }
)
}
}Monitoring
Vercel Analytics
typescript
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react'
import { SpeedInsights } from '@vercel/speed-insights/next'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
)
}Error Tracking (Sentry)
bash
npx @sentry/wizard@latest -i nextjstypescript
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
})Summary
- Vercel - Best for Next.js, easiest deployment
- Railway - Good all-in-one with databases
- Docker - For custom deployment needs
- CI/CD - Automate testing and deployment
- Monitoring - Track errors and performance