Some_claude_skills vercel-deployment
Deploy Next.js and React applications to Vercel — project setup, environment variables, edge functions, build troubleshooting, preview deployments, monorepo configuration. NOT for AWS/GCP/Azure
git clone https://github.com/curiositech/some_claude_skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/curiositech/some_claude_skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/vercel-deployment" ~/.claude/skills/erichowens-some-claude-skills-vercel-deployment && rm -rf "$T"
.claude/skills/vercel-deployment/SKILL.mdVercel Deployment
This skill helps you deploy and configure Next.js applications on Vercel following best practices.
Quick Deploy Checklist
- Environment variables set in Vercel dashboard
- Build command configured (default:
)next build - Output directory correct (default:
).next - Node.js version specified (20.x recommended)
- Database accessible from Vercel's network
- Secrets not committed to git
Environment Variables
Setting Variables
Vercel Dashboard (Recommended for secrets):
- Project Settings → Environment Variables
- Add variable with appropriate scope:
- Production: Only production deployments
- Preview: PR and branch previews
- Development: Local
vercel dev
Via CLI:
vercel env add VARIABLE_NAME production vercel env pull .env.local # Pull to local
Variable Naming
# Server-only (never exposed to browser) DATABASE_URL= SESSION_SECRET= ANTHROPIC_API_KEY= # Client-exposed (prefixed with NEXT_PUBLIC_) NEXT_PUBLIC_APP_URL= NEXT_PUBLIC_ANALYTICS_ID=
Size Limits
| Context | Limit |
|---|---|
| Total per deployment | 64 KB |
| Edge Functions | 5 KB per variable |
| Single variable | 64 KB max |
Required Variables for This Project
# Authentication (required) SESSION_SECRET=your-32-char-minimum-secret-here # AI Integration (required for chat) ANTHROPIC_API_KEY=sk-ant-api... # Database (if using external) DATABASE_URL=file:./data/app.db # Push Notifications (optional) VAPID_PUBLIC_KEY= VAPID_PRIVATE_KEY= VAPID_SUBJECT=mailto:admin@example.com # OAuth (optional) GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= GITHUB_CLIENT_ID= GITHUB_CLIENT_SECRET= APPLE_CLIENT_ID= APPLE_CLIENT_SECRET=
vercel.json Configuration
{ "buildCommand": "npm run build", "framework": "nextjs", "regions": ["iad1"], "headers": [ { "source": "/api/(.*)", "headers": [ { "key": "Cache-Control", "value": "no-store, must-revalidate" } ] }, { "source": "/(.*)", "headers": [ { "key": "X-Content-Type-Options", "value": "nosniff" }, { "key": "X-Frame-Options", "value": "DENY" }, { "key": "X-XSS-Protection", "value": "1; mode=block" } ] } ], "redirects": [ { "source": "/old-path", "destination": "/new-path", "permanent": true } ], "rewrites": [ { "source": "/api/v1/:path*", "destination": "/api/:path*" } ] }
TypeScript Configuration (New in 2025)
// vercel.ts - Type-safe configuration import { defineConfig } from '@vercel/config'; export default defineConfig({ regions: ['iad1'], headers: async () => [ { source: '/api/:path*', headers: [ { key: 'Cache-Control', value: 'no-store' }, ], }, ], redirects: async () => [ { source: '/old', destination: '/new', permanent: true, }, ], });
Edge Functions
When to Use Edge
Good for:
- Authentication/authorization
- A/B testing
- Geolocation-based content
- Request/response transforms
- Simple, fast operations
Not suitable for:
- Database connections (use serverless instead)
- Long-running operations
- Large dependencies
Edge Function Example
// src/middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export const config = { matcher: ['/api/:path*', '/protected/:path*'], }; export function middleware(request: NextRequest) { // Check auth token const token = request.cookies.get('session')?.value; if (!token && request.nextUrl.pathname.startsWith('/protected')) { return NextResponse.redirect(new URL('/login', request.url)); } // Add headers const response = NextResponse.next(); response.headers.set('X-Request-Id', crypto.randomUUID()); return response; }
Edge Runtime in API Routes
// src/app/api/edge-example/route.ts export const runtime = 'edge'; export async function GET(request: Request) { // Limited to edge-compatible APIs return Response.json({ timestamp: Date.now() }); }
Build Configuration
package.json Scripts
{ "scripts": { "build": "next build", "postbuild": "npm run db:generate" } }
Build Environment
# Set Node.js version # In Vercel Dashboard → Settings → General → Node.js Version # Or in package.json: { "engines": { "node": "20.x" } }
Build Output
# Check build locally npm run build # Analyze bundle ANALYZE=true npm run build
Database Considerations
SQLite on Vercel
SQLite with better-sqlite3 works in Vercel's serverless functions, but:
- Filesystem is read-only except
/tmp - Data doesn't persist between invocations
- Not suitable for production data storage
Production Database Options
-
Turso (SQLite edge database)
import { createClient } from '@libsql/client'; const db = createClient({ url: process.env.TURSO_DATABASE_URL!, authToken: process.env.TURSO_AUTH_TOKEN, }); -
Vercel Postgres
import { sql } from '@vercel/postgres'; const result = await sql`SELECT * FROM users`; -
PlanetScale (MySQL)
-
Neon (Postgres)
Preview Deployments
Branch Previews
Every git push creates a preview deployment:
https://<project>-<branch>-<team>.vercel.app- Separate environment variables for preview
Preview Environment Variables
# Different values for preview vs production # In Vercel Dashboard, set both: DATABASE_URL (Production): postgres://prod-db... DATABASE_URL (Preview): postgres://staging-db...
Commenting on PRs
Vercel automatically comments on PRs with:
- Preview URL
- Build status
- Performance metrics
Troubleshooting
Build Failures
# Check build locally first npm run build # Common issues: # - Missing environment variables # - TypeScript errors # - ESLint errors (strict mode) # - Missing dependencies
Environment Variable Issues
# Verify variables are set vercel env ls # Pull to local for debugging vercel env pull .env.local
Function Timeout
// Increase timeout (max 60s on Pro, 10s on Hobby) // In vercel.json: { "functions": { "api/long-running.ts": { "maxDuration": 60 } } }
Memory Issues
// Increase memory (affects cost) { "functions": { "api/heavy-processing.ts": { "memory": 1024 } } }
Monitoring
Vercel Analytics
// src/app/layout.tsx import { Analytics } from '@vercel/analytics/react'; export default function RootLayout({ children }) { return ( <html> <body> {children} <Analytics /> </body> </html> ); }
Speed Insights
import { SpeedInsights } from '@vercel/speed-insights/next'; export default function RootLayout({ children }) { return ( <html> <body> {children} <SpeedInsights /> </body> </html> ); }
Function Logs
# View logs via CLI vercel logs <deployment-url> # Real-time logs vercel logs <deployment-url> --follow
Domains
Custom Domain Setup
- Vercel Dashboard → Domains
- Add domain
- Configure DNS:
- A record:
76.76.21.21 - Or CNAME:
cname.vercel-dns.com
- A record:
- SSL automatically provisioned
Redirects
// vercel.json { "redirects": [ { "source": "/:path((?!api/).*)", "has": [{ "type": "host", "value": "old-domain.com" }], "destination": "https://new-domain.com/:path", "permanent": true } ] }
Security
Protected Routes
Use middleware for authentication checks (see Edge Functions above).
Rate Limiting
Implement application-level rate limiting since Vercel doesn't provide built-in rate limiting for serverless functions.
Secrets Management
- Never commit
files.env - Use Vercel's encrypted environment variables
- Rotate secrets regularly
- Different secrets for preview vs production