Claude Code Plugins

Community-maintained marketplace

Feedback

deploying-to-production

@chriscarterux/chris-claude-stack
1
0

This skill should be used when deploying applications to production environments including Vercel, Fly.io, Hostinger VPS, or other platforms - covers environment management, zero-downtime deployments, Docker best practices, database migrations, rollback procedures, and health monitoring.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name deploying-to-production
description This skill should be used when deploying applications to production environments including Vercel, Fly.io, Hostinger VPS, or other platforms - covers environment management, zero-downtime deployments, Docker best practices, database migrations, rollback procedures, and health monitoring.

Deploying to Production

Overview

Deploy applications safely and reliably across multiple platforms. This skill provides systematic deployment workflows, environment management, and operational best practices.

Core principle: Deployments should be boring, predictable, and reversible.

When to Use

Use this skill when:

  • Deploying applications to production
  • Setting up CI/CD pipelines
  • Configuring environment variables and secrets
  • Planning database migrations
  • Implementing zero-downtime deployment strategies
  • Setting up monitoring and health checks
  • Planning rollback procedures

Platforms covered:

  • Vercel (Next.js, frontend apps)
  • Fly.io (full-stack apps, APIs)
  • Hostinger VPS (Docker, manual deployments)
  • General Docker/docker-compose patterns

Platform Selection Guide

Platform Best For Deploy Time Cost (Est.)
Vercel Next.js, Static sites, Serverless APIs <2 min Free tier generous, $20+/mo pro
Fly.io Full-stack apps, APIs, Databases <5 min $0-10/mo small apps
Hostinger VPS Full control, Docker apps, Databases <10 min Fixed VPS cost
Railway Quick prototypes, Postgres + App <3 min $5+/mo
Render Web services, Cron jobs, Databases <5 min Free tier, $7+/mo

Vercel Deployment

Initial Setup

# Install Vercel CLI
npm i -g vercel

# Login
vercel login

# Deploy from project directory
vercel

# Production deployment
vercel --prod

Environment Variables

Via CLI:

# Add environment variable
vercel env add VARIABLE_NAME

# Pull environment variables locally
vercel env pull .env.local

Via Dashboard:

  1. Project Settings → Environment Variables
  2. Add variables for each environment (Production, Preview, Development)
  3. Redeploy for changes to take effect

Automatic Deployments

Setup via GitHub:

  1. Push code to GitHub
  2. Import project in Vercel dashboard
  3. Configure build settings:
    • Framework Preset: Next.js (auto-detected)
    • Build Command: npm run build
    • Output Directory: .next (auto-detected)
    • Install Command: npm install

Deployment triggers:

  • Push to main → Production deployment
  • Push to other branches → Preview deployment
  • Pull requests → Preview deployment with unique URL

Database Connections

Vercel Postgres (managed):

# Create database
vercel postgres create

# Get connection string
vercel env add POSTGRES_URL

External database (Supabase, PlanetScale):

# Add connection string as environment variable
vercel env add DATABASE_URL

Custom Domains

# Add domain via CLI
vercel domains add yourdomain.com

# Or via dashboard: Settings → Domains

DNS Configuration:

  • Add CNAME record: wwwcname.vercel-dns.com
  • Add A record: @76.76.21.21

Fly.io Deployment

Initial Setup

# Install flyctl
curl -L https://fly.io/install.sh | sh

# Login
fly auth login

# Create app (generates fly.toml)
fly launch

# Deploy
fly deploy

fly.toml Configuration

app = "your-app-name"
primary_region = "iad"  # or closest to your users

[build]
  dockerfile = "Dockerfile"

[env]
  PORT = "8080"
  # Public env vars only

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = "stop"
  auto_start_machines = true
  min_machines_running = 0
  processes = ["app"]

[[vm]]
  memory = "256mb"
  cpu_kind = "shared"
  cpus = 1

Environment Variables

# Set secrets (encrypted)
fly secrets set DATABASE_URL=postgres://...
fly secrets set API_KEY=secret123

# List secrets
fly secrets list

# Remove secret
fly secrets unset API_KEY

Persistent Storage (Volumes)

# Create volume
fly volumes create data --size 1

# Add to fly.toml
[[mounts]]
  source = "data"
  destination = "/data"

Database on Fly.io

# Create Postgres cluster
fly postgres create

# Attach to app
fly postgres attach --app your-app-name your-postgres-app

Scaling

# Scale machine count
fly scale count 2

# Scale VM size
fly scale vm shared-cpu-2x

# Scale memory
fly scale memory 512

Deployments & Rollback

# Deploy
fly deploy

# View releases
fly releases

# Rollback to previous version
fly releases rollback <version>

Hostinger VPS Deployment

Initial VPS Setup

# SSH into VPS
ssh root@your-vps-ip

# Update system
apt update && apt upgrade -y

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

# Install Docker Compose
apt install docker-compose-plugin

# Verify
docker --version
docker compose version

Project Structure for VPS

your-app/
├── docker-compose.yml
├── Dockerfile (if custom)
├── .env (secrets, not in git)
├── nginx.conf (if using nginx)
└── your-app-files/

docker-compose.yml Example

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=${DATABASE_URL}
    env_file:
      - .env
    restart: unless-stopped
    volumes:
      - ./data:/app/data

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - app
    restart: unless-stopped

volumes:
  postgres_data:

Deployment Workflow

# On VPS: Clone or pull latest code
cd /root
git clone https://github.com/your-repo.git
cd your-repo

# Create .env file (never commit this!)
nano .env
# Add: DATABASE_URL=...
#      API_KEY=...
#      etc.

# Build and start
docker compose up -d --build

# View logs
docker compose logs -f

# Stop
docker compose down

# Update deployment
git pull
docker compose up -d --build

Zero-Downtime Updates

# Build new version
docker compose build app

# Scale up new instance
docker compose up -d --scale app=2

# Health check new instance
# (verify it's working)

# Remove old instance
docker compose up -d --scale app=1

# Or use docker-compose rolling updates
docker compose up -d --no-deps --build app

SSL/HTTPS Setup

Using Certbot (Let's Encrypt):

# Install certbot
apt install certbot python3-certbot-nginx

# Get certificate
certbot --nginx -d yourdomain.com -d www.yourdomain.com

# Auto-renewal (certbot installs cron job automatically)
certbot renew --dry-run

Monitoring & Health Checks

# Check running containers
docker ps

# View resource usage
docker stats

# Check logs
docker compose logs -f app

# Restart unhealthy container
docker compose restart app

Docker Best Practices

Dockerfile Optimization

# Use specific versions, not latest
FROM node:20-alpine

# Set working directory
WORKDIR /app

# Copy package files first (better caching)
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy source code
COPY . .

# Build if needed
RUN npm run build

# Use non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

# Expose port
EXPOSE 3000

# Health check
HEALTHCHECK --interval=30s --timeout=3s \
  CMD node healthcheck.js || exit 1

# Start app
CMD ["npm", "start"]

.dockerignore

node_modules
npm-debug.log
.git
.gitignore
.env*
.next
.DS_Store
README.md
docker-compose*.yml

Multi-Stage Builds

# 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/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

EXPOSE 3000
CMD ["node", "server.js"]

Environment Management

Environment Variable Hierarchy

1. Production (.env.production)
   - DATABASE_URL
   - API_KEYS
   - SECRETS

2. Staging (.env.staging)
   - Test database
   - Sandbox API keys

3. Development (.env.local)
   - Local database
   - Test API keys

Never Commit Secrets

.gitignore must include:

.env
.env.local
.env.production
.env.staging
*.pem
*.key
secrets/

Secret Management Patterns

Option 1: Platform Environment Variables

  • Vercel: Dashboard → Environment Variables
  • Fly.io: fly secrets set KEY=value
  • VPS: .env file on server (not in git)

Option 2: Secret Management Service

# Using Doppler (example)
doppler setup
doppler secrets set API_KEY=secret123
doppler run -- npm start

Option 3: Docker Secrets (Swarm)

# Create secret
echo "secret_value" | docker secret create db_password -

# Use in docker-compose.yml
services:
  app:
    secrets:
      - db_password

Database Migrations

Pre-Deployment Checklist

  • Backup database
  • Test migration locally
  • Test migration on staging
  • Plan rollback procedure
  • Schedule during low-traffic window (if possible)

Migration Strategies

Option 1: Automated (Prisma example)

# Generate migration
npx prisma migrate dev --name add_user_role

# Apply in production
npx prisma migrate deploy

Option 2: Manual SQL

# Connect to production database
psql $DATABASE_URL

# Run migration
\i migrations/001_add_column.sql

# Verify
\dt
SELECT * FROM users LIMIT 1;

Option 3: Zero-Downtime Migrations

-- Step 1: Add new column (nullable)
ALTER TABLE users ADD COLUMN new_field VARCHAR(255);

-- Step 2: Deploy code that writes to both old and new
-- (deploy application update)

-- Step 3: Backfill data
UPDATE users SET new_field = old_field WHERE new_field IS NULL;

-- Step 4: Make column NOT NULL
ALTER TABLE users ALTER COLUMN new_field SET NOT NULL;

-- Step 5: Deploy code that only uses new field
-- (deploy application update)

-- Step 6: Drop old column
ALTER TABLE users DROP COLUMN old_field;

Health Checks & Monitoring

Health Check Endpoint

// app/api/health/route.ts
import { NextResponse } from 'next/server'

export async function GET() {
  try {
    // Check database connection
    await prisma.$queryRaw`SELECT 1`

    // Check external services
    // await checkRedis()
    // await checkS3()

    return NextResponse.json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
    })
  } catch (error) {
    return NextResponse.json(
      { status: 'unhealthy', error: error.message },
      { status: 503 }
    )
  }
}

Monitoring Setup

Free Options:

  • UptimeRobot: HTTP monitoring, free tier
  • BetterUptime: Status pages, free tier
  • Sentry: Error tracking, free tier

Configure monitoring:

# Uptime monitoring
# Add /api/health endpoint to UptimeRobot
# Configure alerts (email, Slack, etc.)

# Error tracking with Sentry
npm install @sentry/nextjs
npx @sentry/wizard -i nextjs

Logging Best Practices

// Use structured logging
import pino from 'pino'

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  formatters: {
    level: (label) => ({ level: label }),
  },
})

logger.info({ userId: 123, action: 'login' }, 'User logged in')
logger.error({ error: err, context: 'payment' }, 'Payment failed')

Rollback Procedures

Vercel Rollback

# View deployments
vercel ls

# Rollback to previous deployment
vercel rollback [deployment-url]

# Or via dashboard: Deployments → ... → Promote to Production

Fly.io Rollback

# View release history
fly releases

# Rollback
fly releases rollback <version-number>

VPS Rollback

Using Git tags:

# Tag before deploying
git tag -a v1.2.3 -m "Production release 1.2.3"
git push origin v1.2.3

# Rollback to tag
git checkout v1.2.2
docker compose up -d --build

Using Docker image tags:

# Tag images before deploying
docker tag app:latest app:v1.2.3

# Rollback
docker compose stop app
docker run -d app:v1.2.2

Database rollback:

# Restore from backup
pg_restore -d mydb backup.dump

# Or run reverse migration
psql $DATABASE_URL < migrations/rollback/001_down.sql

Deployment Checklist

Before deploying:

  • Code reviewed and tested
  • Tests passing
  • Environment variables configured
  • Database migrations planned
  • Backup of current database
  • Rollback plan documented
  • Health check endpoint working
  • Monitoring configured

During deployment:

  • Run database migrations
  • Deploy application
  • Verify health check passes
  • Smoke test critical features
  • Monitor error rates
  • Check logs for issues

After deployment:

  • Verify critical user flows
  • Monitor performance metrics
  • Check error tracking dashboard
  • Communicate deployment to team
  • Tag release in git
  • Document any issues encountered

Common Issues & Solutions

Issue Solution
"Out of memory" on deploy Increase VM size or optimize build process
Environment variables not working Rebuild/restart after changing env vars
Database connection timeout Check firewall rules, connection string
SSL certificate errors Verify DNS propagation, renew certificate
"Port already in use" Stop conflicting process or use different port
Slow cold starts Increase min instances or use edge functions
Build failures Check build logs, verify dependencies installed

Platform-Specific Commands Reference

Vercel

vercel                    # Deploy to preview
vercel --prod            # Deploy to production
vercel env ls            # List environment variables
vercel logs              # View logs
vercel domains ls        # List domains

Fly.io

fly deploy               # Deploy app
fly status               # Check app status
fly logs                 # Stream logs
fly secrets list         # List secrets
fly scale show           # Show current scaling
fly ssh console          # SSH into VM

Docker/VPS

docker compose up -d          # Start services
docker compose down           # Stop services
docker compose logs -f        # Follow logs
docker compose ps             # List containers
docker system prune -a        # Clean up unused images

Resources

Documentation:

Tools:

  • GitHub Actions (CI/CD)
  • Sentry (Error tracking)
  • UptimeRobot (Monitoring)
  • Doppler (Secret management)

Best Practices:

Deployments should be routine and stress-free. With proper environment management, health checks, and rollback procedures, you can deploy confidently and recover quickly when issues arise.