Vercel Deployment
Vercel platform expertise — Next.js deployment, serverless/edge functions, environment variables, preview deployments, domains, and monorepo support
Vercel is the platform built by the creators of Next.js, optimized for frontend frameworks with zero-configuration deployments. Every git push produces an immutable deployment with a unique URL. The platform embraces the "preview everything" model: every branch and PR gets its own live environment. Serverless and edge functions run close to users without managing infrastructure. The goal is to ship fast, preview confidently, and scale automatically. ## Key Points - **Use edge runtime for latency-sensitive routes** — middleware, geolocation, A/B testing, and simple API responses run fastest at the edge. - **Leverage ISR (Incremental Static Regeneration)** — set `revalidate` on pages to serve stale content while regenerating in the background. - **Scope environment variables by environment** — use the Vercel dashboard to set different values for Production, Preview, and Development. - **Protect preview deployments** — enable Vercel Authentication or use password protection for sensitive previews. - **Use `CRON_SECRET`** — always validate the authorization header in cron endpoints to prevent unauthorized invocation. - **Set `maxDuration`** — explicitly configure function timeout to avoid unexpected termination on long-running tasks. - **Cache aggressively at the CDN** — use `s-maxage` and `stale-while-revalidate` headers on API responses that tolerate staleness. - **Use Vercel KV or Blob for state** — avoid writing to the filesystem in serverless functions; use managed storage primitives instead. - **Writing to `/tmp` expecting persistence** — serverless functions are stateless; files in `/tmp` disappear between invocations. Use a database or object store. - **Deploying large monoliths as a single function** — split into multiple API routes. Each route becomes its own serverless function with independent scaling. - **Hardcoding URLs instead of using `VERCEL_URL`** — this breaks preview deployments. Always derive base URLs from the environment. - **Using `runtime: "edge"` with Node.js-only packages** — edge functions run V8, not Node.js. Libraries using `fs`, `net`, or native modules will fail.
skilldb get deployment-hosting-services-skills/Vercel DeploymentFull skill: 278 linesVercel Deployment
Core Philosophy
Vercel is the platform built by the creators of Next.js, optimized for frontend frameworks with zero-configuration deployments. Every git push produces an immutable deployment with a unique URL. The platform embraces the "preview everything" model: every branch and PR gets its own live environment. Serverless and edge functions run close to users without managing infrastructure. The goal is to ship fast, preview confidently, and scale automatically.
Setup
Project Initialization
// vercel.json — project configuration at repo root
{
"buildCommand": "npm run build",
"outputDirectory": ".next",
"framework": "nextjs",
"regions": ["iad1", "sfo1", "cdg1"],
"env": {
"NEXT_PUBLIC_API_URL": "@api-url"
},
"headers": [
{
"source": "/api/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "no-store" }
]
}
]
}
CLI Deployment
// Install and link project
// $ npm i -g vercel
// $ vercel link
// $ vercel env pull .env.local
// Deploy preview
// $ vercel
// Deploy to production
// $ vercel --prod
Environment Variables
// vercel.json — reference Vercel environment variables
{
"env": {
"DATABASE_URL": "@database-url-production",
"STRIPE_SECRET_KEY": "@stripe-secret"
}
}
// Access in Next.js API route
// app/api/config/route.ts
import { NextResponse } from "next/server";
export async function GET() {
// Server-side only — never prefix with NEXT_PUBLIC_
const dbUrl = process.env.DATABASE_URL;
return NextResponse.json({ status: "connected" });
}
Key Techniques
Serverless Functions
// app/api/users/route.ts — App Router API route (runs as serverless)
import { NextRequest, NextResponse } from "next/server";
export const runtime = "nodejs"; // default serverless runtime
export const maxDuration = 30; // seconds (Pro plan: up to 300)
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const page = parseInt(searchParams.get("page") ?? "1", 10);
const users = await fetchUsersFromDB(page);
return NextResponse.json(users, {
headers: { "Cache-Control": "s-maxage=60, stale-while-revalidate=300" },
});
}
export async function POST(request: NextRequest) {
const body = await request.json();
const user = await createUser(body);
return NextResponse.json(user, { status: 201 });
}
Edge Functions
// app/api/geo/route.ts — runs on Vercel Edge Network globally
import { NextRequest, NextResponse } from "next/server";
export const runtime = "edge";
export async function GET(request: NextRequest) {
const country = request.headers.get("x-vercel-ip-country") ?? "US";
const city = request.headers.get("x-vercel-ip-city") ?? "Unknown";
const region = request.headers.get("x-vercel-ip-country-region") ?? "";
return NextResponse.json({ country, city, region });
}
Middleware (Edge)
// middleware.ts — runs before every matched request at the edge
import { NextRequest, NextResponse } from "next/server";
export function middleware(request: NextRequest) {
const token = request.cookies.get("session-token")?.value;
if (request.nextUrl.pathname.startsWith("/dashboard") && !token) {
return NextResponse.redirect(new URL("/login", request.url));
}
const response = NextResponse.next();
response.headers.set("x-request-id", crypto.randomUUID());
return response;
}
export const config = {
matcher: ["/dashboard/:path*", "/api/protected/:path*"],
};
Preview Deployments and Branch Environments
// vercel.json — configure preview-specific behavior
{
"git": {
"deploymentEnabled": {
"main": true,
"staging": true
}
},
"redirects": [
{
"source": "/old-page",
"destination": "/new-page",
"permanent": true
}
]
}
// Use VERCEL_ENV to detect environment in code
// app/lib/config.ts
export function getConfig() {
const env = process.env.VERCEL_ENV; // "production" | "preview" | "development"
const url = process.env.VERCEL_URL; // auto-assigned deployment URL
return {
isProduction: env === "production",
baseUrl: env === "production"
? "https://myapp.com"
: `https://${url}`,
};
}
Monorepo Support
// vercel.json at repo root for monorepo
{
"projects": [
{
"name": "web",
"rootDirectory": "apps/web",
"framework": "nextjs"
},
{
"name": "docs",
"rootDirectory": "apps/docs",
"framework": "nextjs"
}
]
}
// turbo.json — Turborepo integration (auto-detected)
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
}
}
}
Cron Jobs
// vercel.json — define cron schedules
{
"crons": [
{
"path": "/api/cron/sync-data",
"schedule": "0 */6 * * *"
}
]
}
// app/api/cron/sync-data/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const authHeader = request.headers.get("authorization");
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
await syncExternalData();
return NextResponse.json({ synced: true });
}
Custom Domains and Rewrites
// vercel.json
{
"rewrites": [
{ "source": "/blog/:slug", "destination": "/api/blog/:slug" },
{ "source": "/app/:path*", "destination": "https://app.example.com/:path*" }
],
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains" }
]
}
]
}
Best Practices
- Use edge runtime for latency-sensitive routes — middleware, geolocation, A/B testing, and simple API responses run fastest at the edge.
- Leverage ISR (Incremental Static Regeneration) — set
revalidateon pages to serve stale content while regenerating in the background. - Scope environment variables by environment — use the Vercel dashboard to set different values for Production, Preview, and Development.
- Protect preview deployments — enable Vercel Authentication or use password protection for sensitive previews.
- Use
CRON_SECRET— always validate the authorization header in cron endpoints to prevent unauthorized invocation. - Set
maxDuration— explicitly configure function timeout to avoid unexpected termination on long-running tasks. - Cache aggressively at the CDN — use
s-maxageandstale-while-revalidateheaders on API responses that tolerate staleness. - Use Vercel KV or Blob for state — avoid writing to the filesystem in serverless functions; use managed storage primitives instead.
Anti-Patterns
- Writing to
/tmpexpecting persistence — serverless functions are stateless; files in/tmpdisappear between invocations. Use a database or object store. - Deploying large monoliths as a single function — split into multiple API routes. Each route becomes its own serverless function with independent scaling.
- Hardcoding URLs instead of using
VERCEL_URL— this breaks preview deployments. Always derive base URLs from the environment. - Using
runtime: "edge"with Node.js-only packages — edge functions run V8, not Node.js. Libraries usingfs,net, or native modules will fail. - Ignoring function size limits — keep serverless function bundles under 50MB (250MB uncompressed). Tree-shake dependencies and avoid bundling unnecessary packages.
- Skipping the build cache — avoid
vercel --forcein CI unless debugging; the cache dramatically speeds up builds. - Using
getServerSidePropseverywhere — prefer static generation or ISR when data does not change per-request. SSR on every request increases latency and cost.
Install this skill directly: skilldb add deployment-hosting-services-skills
Related Skills
AWS Lightsail
AWS Lightsail provides a simplified way to launch virtual private servers (VPS), containers, databases, and more. It's ideal for developers and small businesses needing easy-to-use, cost-effective cloud resources without deep AWS expertise.
Cloudflare Pages Deployment
Cloudflare Pages and Workers expertise — edge-first deployments, full-stack apps with Workers functions, KV/D1/R2 bindings, preview URLs, custom domains, and global CDN distribution
Coolify Deployment
Coolify self-hosted PaaS expertise — Docker-based deployments, Git integration, automatic SSL, database provisioning, server management, and Heroku/Netlify alternative on your own hardware
Digital Ocean App Platform
DigitalOcean App Platform is a fully managed Platform-as-a-Service (PaaS) that allows you to quickly build, deploy, and scale web applications, static sites, APIs, and background services. It integrates seamlessly with other DigitalOcean services like Managed Databases and Spaces, making it ideal for developers seeking a streamlined, opinionated deployment experience within the DO ecosystem.
Fly.io Deployment
Fly.io platform expertise — container deployment, global edge distribution, Dockerfiles, volumes, secrets, scaling, PostgreSQL, and multi-region patterns
Google Cloud Run
Google Cloud Run is a fully managed serverless platform for containerized applications. It allows you to deploy stateless containers that scale automatically from zero to thousands of instances based on request load, paying only for the resources consumed. Choose Cloud Run for microservices, web APIs, and event-driven functions that require custom runtimes or environments.