Deploying Vercel + Docker
With MegaShop development complete, Charlie needs to deploy it to the production environment. Vercel offers a simple deployment process but has limited customization options, while Docker provides full control but involves complex configuration. Bob needs a deployment solution that's both flexible and reliable—using Vercel for the front end and API, and Docker for the database and Redis.
1. What You'll Learn
- Vercel Deployment: Zero Configuration + Nitro Preset + Environment Variables
- Docker Deployment: Dockerfile + Multistage Build + docker-compose
- Node.js Deployment: standalone preset + PM2
- Static hosting: Cloudflare Pages / Netlify / S3
- Hands-On Guide to Deploying MegaShop in Production: Vercel + Docker Compose
2. A True Story of an Architect
(1) Pain Point: Being able to run production environments locally
Charlie's MegaShop ran perfectly locally, but after deploying it to the server—environment variables were missing, the database couldn't be connected to, Redis wasn't running, and there were port conflicts. It took Bob five tries to successfully deploy it, and he ran into a different issue each time.
(2) The Docker + Vercel Solution
Docker packages the entire runtime environment, and Vercel deploys the frontend with zero configuration:
# Vercel: zero-config deploy
vercel --prod
# Docker: build once, run anywhere
docker compose up -d
(3) Benefits: One-click deployment + Consistent environments
Charlie uses git push to trigger Vercel deployment for the frontend and Docker Compose to manage the database, Redis, and Nuxt services, ensuring a completely consistent environment.
3. Deploying to Vercel
(1) Multi-platform Deployment of Decision Trees
flowchart TB
A[Deploy Nuxt 3 App] --> B{Need SSR?}
B -->|No| C[Static Hosting<br/>Cloudflare/Netlify/S3]
B -->|Yes| D{Team size?}
D -->|Small/Medium| E[Vercel<br/>Zero-config deploy]
D -->|Large/Enterprise| F[Docker + Node.js<br/>Full control]
E --> G[API + Frontend on Vercel]
F --> H[Docker Compose<br/>Nuxt + PostgreSQL + Redis]
(1) ▶ Example: Zero-Configuration Deployment on Vercel
# Install Vercel CLI
npm i -g vercel
# Deploy (auto-detects Nuxt 3)
vercel
# Production deploy
vercel --prod
Output:
# Command executed successfully
(2) ▶ Example: nuxt.config.ts Vercel configuration
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'vercel' // Auto-configured by Vercel
},
// Environment variables set in Vercel dashboard
runtimeConfig: {
databaseUrl: process.env.DATABASE_URL,
redisUrl: process.env.REDIS_URL,
public: {
apiBase: process.env.API_BASE
}
}
})
Output:
// Execution Successful
(2) Pros and Cons of Vercel Deployment
| Dimension | Vercel | Docker |
|---|---|---|
| Configuration Complexity | 🟢 Zero configuration | 🔴 Requires writing a Dockerfile |
| Deployment Speed | ⚡ 30s | 🟡 3-5 min build |
| Custom | 🔴 Restricted | 🟢 Full Control |
| Database | 🔴 Requires an external service (Vercel Postgres) | 🟢 Local deployment |
| Cost | ⚠️ Billed per request | 🟢 Fixed server fee |
| Extension | 🟢 Automatic | 🟡 Manual/K8s |
4. Docker Deployment
(1) ▶ Example: Multi-stage Dockerfile
# Dockerfile
# Stage 1: Install dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npx prisma generate
RUN npm run build
# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Copy built assets
COPY --from=builder /app/.output ./.output
COPY --from=builder /app/prisma ./prisma
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]
Output:
// Execution Successful
(2) ▶ Example: Docker Compose Orchestration
# docker-compose.yml
version: '3.8'
services:
# Nuxt application
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://megashop:megashop_pass@db:5432/megashop
- REDIS_URL=redis://redis:6379
- JWT_ACCESS_SECRET=${JWT_ACCESS_SECRET}
- JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET}
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
# PostgreSQL database
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=megashop
- POSTGRES_PASSWORD=megashop_pass
- POSTGRES_DB=megashop
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U megashop"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
# Redis cache
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: unless-stopped
# Nginx reverse proxy
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- web
restart: unless-stopped
volumes:
postgres_data:
redis_data:
Output:
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
(3) ▶ Example: Nginx Reverse Proxy Configuration
# nginx.conf
events {
worker_connections 1024;
}
http {
upstream nuxt {
server web:3000;
}
server {
listen 80;
server_name megashop.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name megashop.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
location / {
proxy_pass http://nuxt;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Cache static assets
location /_nuxt/ {
proxy_pass http://nuxt;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
Output:
// Execution Successful
5. Node.js Standalone + PM2
(1) ▶ Example: Building a Standalone Preset
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'node-server',
compressPublicAssets: true
}
})
Output:
// Execution Successful
# Build standalone server
npm run build
# Output: .output/server/index.mjs
# Run directly
node .output/server/index.mjs
(2) ▶ Example: PM2 Process Management
// ecosystem.config.js
module.exports = {
apps: [{
name: 'megashop',
script: '.output/server/index.mjs',
instances: 'max', // Use all CPU cores
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000,
DATABASE_URL: 'postgresql://megashop:pass@localhost:5432/megashop',
REDIS_URL: 'redis://localhost:6379'
},
max_memory_restart: '1G',
error_file: './logs/error.log',
out_file: './logs/out.log',
merge_logs: true,
autorestart: true
}]
}
Output:
// Execution Successful
# Start with PM2
pm2 start ecosystem.config.js
# Monitor
pm2 monit
# Reload (zero-downtime)
pm2 reload megashop
# Logs
pm2 logs megashop
(1) Comparison of Deployment Options
| Solution | Complexity | Manageability | Scalability | Applicability |
|---|---|---|---|---|
| Vercel | 🟢 Low | 🔴 Low | 🟢 Automatic | Small/Medium Teams |
| Docker Compose | 🟡 Medium | 🟢 High | 🟡 Manual | Medium/Large Teams |
| PM2 + Nginx | 🟡 Medium | 🟢 High | 🟡 Manual | VPS Deployment |
| K8s | 🔴 High | 🟢 Highest | 🟢 Auto | Large-scale |
6. Comprehensive Example: MegaShop Production Deployment
# ============================================
# MegaShop Production Deployment
# Docker Compose + Nginx + PostgreSQL + Redis
# ============================================
# 1. Clone and configure
git clone https://github.com/megashop/megashop.git
cd megashop
cp .env.example .env
# Edit .env with production secrets
# 2. Build and start
docker compose up -d --build
# 3. Run database migrations
docker compose exec web npx prisma migrate deploy
# 4. Seed initial data (first time only)
docker compose exec web npx prisma db seed
# 5. Verify
curl https://megashop.com/api/products?limit=5
# 6. Monitor
docker compose logs -f web
❓ FAQ
node-server preset generates standalone output (.output/server/index.mjs), does not require node_modules, and can be run directly.docker compose exec web npx prisma migrate deploy. Or add migration steps to your Dockerfile. For production, use migrate deploy (which does not create new migrations, but only applies existing ones).📖 Summary
- Vercel: Zero-configuration deployment, ideal for small and medium-sized teams, with a unified API and front-end solution
- Use Docker's multi-stage builds to generate optimized images, and use Docker Compose to orchestrate the entire suite of services
- The PM2 cluster mode enables multi-process operation and zero-downtime reloading
- Nginx Reverse Proxy + SSL + Static Resource Caching
- MegaShop Recommends Docker Compose: Nuxt + PostgreSQL + Redis + Nginx
📝 Exercises
- Basic Exercise (Difficulty: ⭐): Deploy MegaShop to Vercel, configure the environment variables, and verify that the SSR pages are working properly.
- Advanced Exercise (Difficulty: ⭐⭐): Write a Dockerfile and docker-compose.yml to launch the complete environment (Nuxt + PostgreSQL + Redis) locally.
- Challenge (Difficulty: ⭐⭐⭐): Implement a complete production deployment using Docker Compose, Nginx, and SSL, and configure health checks and automatic restarts.
---|



