Vercel Deployment Complete Guide 2026: Next.js, Edge Functions, and Analytics
Advertisement
Vercel 2026: The Best Platform for Next.js
Vercel is where Next.js lives. Zero-config deployment, instant previews per PR, global CDN, edge functions — it's the fastest way to get a production-grade app live.
- Getting Started
- vercel.json Configuration
- Environment Variables
- Edge Functions
- Vercel Analytics and Speed Insights
- Preview Deployments for Every PR
- Custom Domains
- Vercel Postgres (Built-in Database)
- ISR: Incremental Static Regeneration
Getting Started
npm install -g vercel
# Deploy
vercel
# Production deploy
vercel --prod
# Deploy with env
vercel --prod --env DATABASE_URL="postgresql://..."
vercel.json Configuration
{
"buildCommand": "npm run build",
"installCommand": "npm ci",
"framework": "nextjs",
"regions": ["iad1", "sin1"],
"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": "/_next/static/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
]
}
],
"rewrites": [
{ "source": "/old-blog/:slug", "destination": "/blog/:slug" }
],
"redirects": [
{ "source": "/about-us", "destination": "/about", "permanent": true }
],
"crons": [
{ "path": "/api/cron/daily-digest", "schedule": "0 8 * * *" }
]
}
Environment Variables
# Set environment variables
vercel env add DATABASE_URL production
vercel env add DATABASE_URL preview
vercel env add DATABASE_URL development
# Pull to local .env.local
vercel env pull
# List all
vercel env ls
// Different variables per environment
// .env.production → used in production
// .env.preview → used in preview deployments
// .env.development → used locally
// next.config.js — expose to browser
const nextConfig = {
env: {
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
},
}
Edge Functions
// app/api/geo-redirect/route.ts — runs at the Edge
import { NextRequest, NextResponse } from 'next/server'
export const runtime = 'edge'
const COUNTRY_REDIRECTS: Record<string, string> = {
IN: 'https://in.webcoderspeed.com',
GB: 'https://uk.webcoderspeed.com',
}
export async function GET(request: NextRequest) {
const country = request.geo?.country || 'US'
const city = request.geo?.city
// Redirect based on geography
if (country in COUNTRY_REDIRECTS) {
return NextResponse.redirect(COUNTRY_REDIRECTS[country])
}
// Personalize response
return NextResponse.json({
message: `Hello from ${city || 'unknown city'}!`,
country,
region: request.geo?.region,
})
}
Vercel Analytics and Speed Insights
// 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 /> {/* Page views and custom events */}
<SpeedInsights /> {/* Real user Core Web Vitals */}
</body>
</html>
)
}
// Track custom events
import { track } from '@vercel/analytics'
function SignupButton() {
return (
<button onClick={() => {
track('signup_clicked', { plan: 'pro', source: 'hero' })
}}>
Sign up
</button>
)
}
Preview Deployments for Every PR
Every pull request gets a unique URL automatically. Enable in your GitHub settings:
# .github/workflows/preview-comment.yml
name: Preview URL Comment
on:
deployment_status:
jobs:
comment:
runs-on: ubuntu-latest
if: github.event.deployment_status.state == 'success'
steps:
- uses: actions/github-script@v7
with:
script: |
const url = context.payload.deployment_status.target_url
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.deployment.payload.pr_number,
body: `✅ Preview deployed: ${url}`
})
Custom Domains
# Add domain
vercel domains add webcoderspeed.com
vercel alias my-project-git-main-username.vercel.app webcoderspeed.com
# SSL is automatic — Let's Encrypt
# DNS: Add CNAME record → cname.vercel-dns.com
Vercel Postgres (Built-in Database)
// Vercel Postgres — PostgreSQL without the ops
import { sql } from '@vercel/postgres'
const { rows } = await sql`
SELECT * FROM posts
WHERE published = true
ORDER BY created_at DESC
LIMIT 10
`
// Works in Edge Runtime too (HTTP-based connection)
ISR: Incremental Static Regeneration
// Generate static at build, revalidate in background
export const revalidate = 3600 // Revalidate every hour
export default async function BlogPage() {
const posts = await getPosts() // Cached for 1 hour
return <PostList posts={posts} />
}
// Or on-demand revalidation from a webhook
// app/api/revalidate/route.ts
export async function POST(request: Request) {
const { secret, slug } = await request.json()
if (secret !== process.env.REVALIDATE_SECRET) {
return Response.json({ error: 'Invalid secret' }, { status: 401 })
}
revalidatePath(`/blog/${slug}`)
return Response.json({ revalidated: true })
}
Vercel's free tier handles most hobby projects. Pro ($20/month) adds team features, higher limits, and Web Analytics. Enterprise for high-traffic production apps.
Advertisement