Deploy frontend and full-stack apps on Vercel with previews, edge functions, and environment promotion.
Ship web apps quickly with preview environments and managed edge infrastructure.
Use this skill when:
# Install CLI
npm i -g vercel
# Login and link project
vercel login
vercel link
# Deploy to preview
vercel
# Deploy to production
vercel --prod
# Pull environment variables locally
vercel env pull .env.local
// vercel.json
{
"framework": "nextjs",
"buildCommand": "npm run build",
"outputDirectory": ".next",
"installCommand": "npm ci",
"regions": ["iad1", "sfo1", "cdg1"],
"headers": [
{
"source": "/api/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "no-store" },
{ "key": "X-Content-Type-Options", "value": "nosniff" }
]
},
{
"source": "/(.*)",
"headers": [
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains" }
]
}
],
"redirects": [
{ "source": "/blog/:slug", "destination": "/posts/:slug", "permanent": true }
],
"rewrites": [
{ "source": "/api/v1/:path*", "destination": "https://api.example.com/:path*" }
]
}
# Add environment variables
vercel env add DATABASE_URL production
vercel env add DATABASE_URL preview
vercel env add NEXT_PUBLIC_API_URL production
# List all env vars
vercel env ls
# Pull to local .env.local
vercel env pull .env.local
# Remove an env var
vercel env rm SECRET_KEY production
# Production — real credentials
vercel env add DATABASE_URL production <<< "postgresql://prod-host:5432/app"
vercel env add STRIPE_SECRET_KEY production
# Preview — staging/test credentials
vercel env add DATABASE_URL preview <<< "postgresql://staging-host:5432/app"
vercel env add STRIPE_SECRET_KEY preview # Use test mode key
# Development — local values
vercel env add DATABASE_URL development <<< "postgresql://localhost:5432/app"
// app/api/geo/route.ts — Edge API route (Next.js App Router)
import { NextRequest } from 'next/server';
export const runtime = 'edge';
export function GET(request: NextRequest) {
const country = request.geo?.country || 'US';
const city = request.geo?.city || 'Unknown';
return Response.json({
country,
city,
region: request.geo?.region,
timestamp: new Date().toISOString(),
});
}
// middleware.ts — Edge middleware for auth/redirects
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Block non-US traffic from admin
if (request.nextUrl.pathname.startsWith('/admin')) {
if (request.geo?.country !== 'US') {
return NextResponse.redirect(new URL('/blocked', request.url));
}
}
// Add security headers
const response = NextResponse.next();
response.headers.set('X-Request-Id', crypto.randomUUID());
return response;
}
export const config = {
matcher: ['/admin/:path*', '/api/:path*'],
};
# .github/workflows/preview.yml
name: Vercel Preview
on: pull_request
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run test
- name: Deploy to Vercel Preview
id: deploy
run: |
npm i -g vercel
URL=$(vercel --token ${{ secrets.VERCEL_TOKEN }} --yes)
echo "url=$URL" >> "$GITHUB_OUTPUT"
- name: Comment PR with preview URL
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Preview deployed: ${{ steps.deploy.outputs.url }}`
});
# Deployments
vercel # Deploy to preview
vercel --prod # Deploy to production
vercel rollback # Rollback last production deploy
vercel promote <url> # Promote preview to production
# Domains
vercel domains add example.com
vercel domains ls
vercel certs ls
# Logs
vercel logs <deployment-url>
vercel logs <deployment-url> --follow
# Project management
vercel project ls
vercel project rm <name>
# Inspect deployment
vercel inspect <deployment-url>
vercel.json headers for security (CSP, HSTS, X-Frame-Options)# Enable Speed Insights in Next.js
npm install @vercel/speed-insights
# Enable Web Analytics
npm install @vercel/analytics
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react';
import { SpeedInsights } from '@vercel/speed-insights/next';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}
| Issue | Solution |
|-------|---------|
| Build fails | Check vercel logs, verify Node.js version in engines field |
| Env vars missing | Run vercel env pull, check variable scope (preview vs production) |
| Edge function timeout | Edge has 30s limit; move heavy work to serverless (no runtime = 'edge') |
| Cold starts slow | Use edge runtime where possible, reduce bundle size |
| Domain not working | Check DNS propagation, verify vercel domains configuration |
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer