Deployment Guide for deploying ShipKit applications to production using Vercel, managing environments, and setting up CI/CD
Deployment
This guide covers deploying ShipKit applications to production environments, with a focus on Vercel deployment, environment configuration, database migrations, and continuous integration/deployment (CI/CD).
Vercel Deployment
Initial Setup
Connect Repository
Log in to Vercel
Import your Git repository
Select the project root directory
Configure Project
# Install Vercel CLI
pnpm add -g vercel
# Login to Vercel
vercel login
# Link local project to Vercel
vercel link
Build Settings
{
"buildCommand": "pnpm build",
"devCommand": "pnpm dev",
"installCommand": "pnpm install --no-frozen-lockfile",
"framework": "nextjs"
}
Environment Configuration
Production Environment
# .env.production
NEXT_PUBLIC_APP_URL="https://your-domain.com"
NEXT_PUBLIC_APP_NAME="ShipKit"
DATABASE_URL="postgresql://user:pass@host:5432/db"
NEXTAUTH_URL="https://your-domain.com"
NEXTAUTH_SECRET="your-secret"
OPENAI_API_KEY="your-key"
RESEND_API_KEY="your-key"
STRIPE_SECRET_KEY="your-key"
STRIPE_WEBHOOK_SECRET="your-secret"
Preview Environment
# .env.preview
NEXT_PUBLIC_APP_URL="https://preview.your-domain.com"
NEXT_PUBLIC_APP_NAME="ShipKit Preview"
DATABASE_URL="postgresql://user:pass@host:5432/preview_db"
NEXTAUTH_URL="https://preview.your-domain.com"
NEXTAUTH_SECRET="preview-secret"
OPENAI_API_KEY="preview-key"
RESEND_API_KEY="preview-key"
STRIPE_SECRET_KEY="preview-key"
STRIPE_WEBHOOK_SECRET="preview-secret"
Domain Configuration
Custom Domain Setup
# Add custom domain
vercel domains add your-domain.com
# Configure DNS
vercel dns add your-domain.com @ A 76.76.21.21
vercel dns add your-domain.com www CNAME cname.vercel-dns.com
SSL Configuration
Vercel automatically provisions SSL certificates
Supports automatic renewal
Enables HTTPS by default
Database Migrations
Production Deployment
# Generate migration
pnpm prisma migrate dev --name init
# Deploy migration
pnpm prisma migrate deploy
# Verify deployment
pnpm prisma migrate status
Rollback Strategy
// prisma/migrations/rollback.ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function rollback() {
try {
await prisma.$executeRawUnsafe('ROLLBACK;')
console.log('Rollback successful')
} catch (error) {
console.error('Rollback failed:', error)
} finally {
await prisma.$disconnect()
}
}
rollback()
CI/CD Pipeline
GitHub Actions
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- run: pnpm install
- run: pnpm test
- run: pnpm test:e2e
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- run: pnpm install
- run: pnpm lint
deploy:
needs: [test, lint]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- run: pnpm install
- run: pnpm build
- 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'
Deployment Checks
# .github/workflows/deployment-check.yml
name: Deployment Check
on:
deployment_status:
jobs:
e2e:
if: github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- run: pnpm install
- name: Run E2E Tests
run: pnpm test:e2e
env:
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
Monitoring
Application Monitoring
Error Tracking
// src/utils/error-tracking.ts
import * as Sentry from '@sentry/nextjs'
export function initErrorTracking() {
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NEXT_PUBLIC_APP_ENV,
tracesSampleRate: 1.0,
})
}
Performance Monitoring
// src/utils/analytics.ts
import { Analytics } from '@vercel/analytics/react'
export function AnalyticsProvider({ children }) {
return (
<>
{children}
<Analytics />
</>
)
}
Health Checks
// src/app/api/health/route.ts
import { NextResponse } from 'next/server'
import { db } from '@/server/db'
export async function GET() {
try {
// Check database connection
await db.$queryRaw`SELECT 1`
return NextResponse.json(
{ status: 'healthy', timestamp: new Date().toISOString() },
{ status: 200 }
)
} catch (error) {
return NextResponse.json(
{ status: 'unhealthy', error: error.message },
{ status: 500 }
)
}
}
Security
Headers Configuration
// next.config.mjs
const securityHeaders = [
{
key: 'X-DNS-Prefetch-Control',
value: 'on'
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload'
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN'
},
{
key: 'X-Content-Type-Options',
value: 'nosniff'
},
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin'
}
]
export default {
headers: async () => [
{
source: '/:path*',
headers: securityHeaders,
},
],
}
Environment Variables
// src/env.mjs
import { createEnv } from '@t3-oss/env-nextjs'
import { z } from 'zod'
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
NEXTAUTH_URL: z.string().url(),
NEXTAUTH_SECRET: z.string().min(32),
OPENAI_API_KEY: z.string().min(32),
RESEND_API_KEY: z.string().min(32),
STRIPE_SECRET_KEY: z.string().min(32),
STRIPE_WEBHOOK_SECRET: z.string().min(32),
},
client: {
NEXT_PUBLIC_APP_URL: z.string().url(),
NEXT_PUBLIC_APP_NAME: z.string(),
},
runtimeEnv: process.env,
})
Deployment Checklist
Pre-deployment
[ ] Run all tests (pnpm test
)
[ ] Check build output (pnpm build
)
[ ] Verify environment variables
[ ] Review security headers
[ ] Check database migrations
Deployment
[ ] Deploy database migrations
[ ] Deploy application
[ ] Verify SSL certificates
[ ] Check custom domain configuration
Post-deployment
[ ] Run health checks
[ ] Verify monitoring setup
[ ] Test critical user flows
[ ] Check error tracking
[ ] Monitor performance metrics
Documentation
[ ] Update API documentation
[ ] Document deployment changes
[ ] Update environment variables
[ ] Review security measures