Marketplace vercel-deploy
install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/awais68/vercel-deploy" ~/.claude/skills/aiskillstore-marketplace-vercel-deploy && rm -rf "$T"
manifest:
skills/awais68/vercel-deploy/SKILL.mdsource content
Vercel Deployment Skill
Expert deployment of Next.js applications to Vercel with optimal build settings, environment configuration, and custom domain setup.
Quick Reference
| Task | File/Command |
|---|---|
| Configure build | |
| Set env vars | Vercel Dashboard or CLI |
| Deploy | |
| Check status | |
| Custom domain | Vercel Dashboard > Settings > Domains |
Project Structure
project/ ├── vercel.json # Vercel configuration ├── next.config.js # Next.js configuration ├── .env.local # Local development (not committed) ├── .env.example # Template (committed) ├── docs/ │ └── deployment.md # Deployment documentation └── frontend/ # Next.js app ├── app/ ├── public/ └── src/
vercel.json Configuration
Basic Configuration
{ "buildCommand": "npm run build", "outputDirectory": ".next", "installCommand": "npm install", "framework": "nextjs", "regions": ["iad1"], "env": { "NEXT_PUBLIC_API_URL": "@api_url" } }
Advanced Configuration with Rewrites
{ "version": 2, "buildCommand": "npm run build", "outputDirectory": ".next", "installCommand": "npm install", "framework": "nextjs", "regions": ["iad1"], "rewrites": [ { "source": "/api/:path*", "destination": "https://api.yourdomain.com/:path*" } ], "headers": [ { "source": "/(.*)", "headers": [ { "key": "X-Content-Type-Options", "value": "nosniff" }, { "key": "X-Frame-Options", "value": "DENY" }, { "key": "X-XSS-Protection", "value": "1; mode=block" } ] }, { "source": "/static/:path*", "headers": [ { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" } ] }, { "source": "/api/:path*", "headers": [ { "key": "Access-Control-Allow-Origin", "value": "*" } ] } ], "redirects": [ { "source": "/old-path/:path*", "destination": "/new-path/:path*", "permanent": true }, { "source": "/www/:path*", "destination": "/:path*", "permanent": true } ] }
Next.js Config Integration
// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { // Output configuration for Vercel output: 'standalone', // Image optimization images: { remotePatterns: [ { protocol: 'https', hostname: 'api.yourdomain.com', pathname: '/uploads/**', }, ], formats: ['image/avif', 'image/webp'], }, // Headers for security async headers() { return [ { source: '/:path*', headers: [ { key: 'X-DNS-Prefetch-Control', value: 'on', }, { key: 'Referrer-Policy', value: 'origin-when-cross-origin', }, ], }, ]; }, // Redirects async redirects() { return [ { source: '/legacy/:path*', destination: '/:path*', permanent: true, }, ]; }, // Experimental features experimental: { serverActions: { allowedOrigins: ['yourdomain.com'], }, }, }; module.exports = nextConfig;
Environment Variables
Variable Naming Convention
| Prefix | Access | Description |
|---|---|---|
| Client + Server | Exposed to browser |
| No prefix | Server only | Backend/API use only |
Required Variables
# .env.example - Copy to .env.local for local dev # API Configuration # Backend API URL (development) NEXT_PUBLIC_API_URL="http://localhost:8000/api/v1" # Authentication NEXT_PUBLIC_AUTH_ENABLED="true" # Feature Flags NEXT_PUBLIC_ENABLE_DARK_MODE="true" NEXT_PUBLIC_SHOW_BETA_FEATURES="false"
Production Variables (Set in Vercel Dashboard)
# Environment variables for Production # API Configuration NEXT_PUBLIC_API_URL="https://api.yourdomain.com" # Optional: Analytics NEXT_PUBLIC_GA_ID="G-XXXXXXXXXX" NEXT_PUBLIC_POSTHOG_KEY="phc_xxx" # Optional: Error tracking NEXT_PUBLIC_SENTRY_DSN="https://xxx@sentry.io/xxx"
Sensitive Variables (Server-Only)
These should NOT have
NEXT_PUBLIC_ prefix:
# Server-only (never exposed to client) API_SECRET_KEY="vercel-secret-key" DATABASE_URL="postgresql://..." REDIS_URL="redis://..."
Vercel CLI Deployment
Installation and Login
# Install Vercel CLI npm i -g vercel # Login to Vercel vercel login # Link to project cd frontend vercel link
Deployment Commands
# Deploy to preview (staging) vercel # Deploy to production vercel --prod # Deploy with environment vercel --env=NODE_ENV=production # Pull environment variables from Vercel vercel env pull .env.local
CI/CD Deployment
# In CI pipeline npm i -g vercel vercel --token=$VERCEL_TOKEN --yes
Custom Domain Setup
Adding Domain in Vercel
- Go to Vercel Dashboard > Project > Settings > Domains
- Add your domain (e.g.,
)yourdomain.com - Configure DNS records
DNS Configuration
# For root domain (yourdomain.com) Type: A Name: @ Value: 76.76.21.21 # For www subdomain Type: CNAME Name: www Value: cname.vercel-dns.com. # For API subdomain (optional) Type: CNAME Name: api Value: cname.vercel-dns.com.
www to Root Redirect
{ "redirects": [ { "source": "/:path*", "destination": "https://yourdomain.com/:path*", "permanent": true } ] }
API Proxy Setup
Option 1: Vercel Rewrites (Recommended)
{ "rewrites": [ { "source": "/api/:path*", "destination": "https://api.yourdomain.com/:path*" } ] }
Option 2: Next.js Rewrite
// next.config.js async rewrites() { return [ { source: '/api/:path*', destination: `${process.env.NEXT_PUBLIC_API_URL}/:path*`, }, ]; }
Edge Function for API (Advanced)
// frontend/app/api/[...route]/route.ts import { NextRequest, NextResponse } from 'next/server'; export async function GET(request: NextRequest) { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/v1/endpoint`, { headers: { 'Authorization': request.headers.get('Authorization') || '', 'Content-Type': 'application/json', }, } ); const data = await response.json(); return NextResponse.json(data); }
Build Optimization
Build Command
# Standard build npm run build # With TypeScript check only npm run build -- --no-lint # Custom build next build
Performance Settings
// next.config.js const nextConfig = { // Enable SWC minifier (faster builds) swcMinify: true, // Compiler options compiler: { removeConsole: process.env.NODE_ENV === 'production', }, // Image optimization images: { deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], }, // Enable react strict mode reactStrictMode: true, // Generate Etag generateEtags: true, };
Bundle Analysis
# Install bundle analyzer npm install -D @next/bundle-analyzer # next.config.js const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); module.exports = withBundleAnalyzer({ // your config });
Error Pages
Custom 404 Page
// frontend/app/not-found.tsx import Link from 'next/link'; export default function NotFound() { return ( <div className="min-h-screen flex flex-col items-center justify-center"> <h1 className="text-4xl font-bold">404 - Page Not Found</h1> <p className="mt-2 text-gray-600"> The page you're looking for doesn't exist. </p> <Link href="/" className="mt-4 px-4 py-2 bg-blue-600 text-white rounded" > Go Home </Link> </div> ); }
Custom 500 Page
// frontend/app/error.tsx 'use client'; export default function Error({ error, reset, }: { error: Error & { digest?: string }; reset: () => void; }) { return ( <div className="min-h-screen flex flex-col items-center justify-center"> <h1 className="text-4xl font-bold">Something went wrong!</h1> <p className="mt-2 text-gray-600"> An unexpected error occurred. </p> <button onClick={() => reset()} className="mt-4 px-4 py-2 bg-blue-600 text-white rounded" > Try Again </button> </div> ); }
Global Error Boundary
// frontend/app/global-error.tsx 'use client'; export default function GlobalError({ error, }: { error: Error & { digest?: string }; }) { return ( <html> <body> <div className="min-h-screen flex items-center justify-center"> <h1 className="text-2xl">Application Error</h1> </div> </body> </html> ); }
Deployment Checklist
- Build succeeds locally:
completes without errorsnpm run build - Build succeeds on Vercel: Deploy preview builds correctly
- Correct API URLs: NEXT_PUBLIC_API_URL points to correct environment
- No sensitive vars exposed: No
prefix on secretsNEXT_PUBLIC_ - 404 page configured: Custom not-found.tsx exists
- 500 page configured: Custom error.tsx exists
- Custom domain set up: DNS records configured correctly
- HTTPS enforced: Automatic SSL certificate
- Redirects configured: www to root or vice versa
- Cache headers set: Static assets properly cached
Deployment Documentation Template
# Deployment Guide ## Quick Deploy [](https://vercel.com/new) ## Environment Variables ### Development ```bash NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1
Production
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
Custom Domain
- Add
in Vercel Dashboard > Settings > Domainsyourdomain.com - Configure DNS:
- A record:
->@76.76.21.21 - CNAME:
->wwwcname.vercel-dns.com
- A record:
Troubleshooting
Build Fails
# Run locally to see error npm run build
Environment Variables Not Working
- Check variable name starts with
for client accessNEXT_PUBLIC_ - Redeploy after adding new variables
404 on Production
- Verify
outputDirectory matches build outputvercel.json - Check page files are in
directory (App Router)app/
## Integration Points | Skill | Integration | |-------|-------------| | `@frontend-nextjs-app-router` | Next.js App Router configuration | | `@env-config` | Environment variable management | | `@tailwind-css` | CSS build optimization | | `@api-route-design` | API routes and rewrites | | `@error-handling` | Custom error pages |