We use cookies to enhance your experience on the site
CodeWorlds
Back to collections
Guide10 min read

Vercel

Vercel is a cloud platform for frontend developers with automatic CI/CD, preview deployments, serverless functions, and edge computing. Learn deployment, configuration, and integrations.

Vercel - Complete guide to the platform for frontend developers

What is Vercel and why does it dominate the frontend hosting market?

Vercel is a cloud platform created by the makers of Next.js that has revolutionized the way we deploy frontend applications. It offers zero-config deployment, automatic CI/CD, preview deployments for every PR, serverless functions, and edge computing - all in one place.

Unlike traditional hosting providers, Vercel was designed with the modern frontend development workflow in mind. Every push to the repository automatically triggers a build and deployment, and every Pull Request gets a unique URL for testing.

Why Vercel?

Zero-config deployment

Code
Bash
# Literally one command
npm i -g vercel
vercel

# Or connect a GitHub repo - every push = automatic deploy

Preview Deployments

Every Pull Request automatically gets:

  • A unique URL for testing
  • A comment in the PR with a link
  • The ability to review changes before merge
Code
TEXT
https://my-app-git-feature-branch-username.vercel.app

Global Edge Network

Vercel deploys your application to 100+ locations around the world. Users get content from the nearest server.

First deployment

Method 1: CLI

Code
Bash
# Install CLI
npm i -g vercel

# Deploy (interactive setup)
vercel

# Deploy to production
vercel --prod

# Deploy with specific configuration
vercel --env NODE_ENV=production

Method 2: GitHub Integration

  1. Go to vercel.com
  2. Click "Add New Project"
  3. Select a repository from GitHub
  4. Vercel will automatically detect the framework and configure the build

Method 3: Import from CLI

Code
Bash
# Clone and deploy right away
npx create-next-app@latest my-app
cd my-app
vercel

Vercel project structure

Code
TEXT
my-project/
├── app/                    # Next.js App Router
├── pages/                  # Next.js Pages Router
├── api/                    # API Routes (serverless functions)
├── public/                 # Static files
├── vercel.json             # Vercel configuration (optional)
└── package.json

vercel.json configuration

Code
JSON
{
  "buildCommand": "npm run build",
  "outputDirectory": ".next",
  "devCommand": "npm run dev",
  "installCommand": "npm install",

  "framework": "nextjs",

  "regions": ["iad1", "cdg1"],

  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Access-Control-Allow-Origin", "value": "*" },
        { "key": "Access-Control-Allow-Methods", "value": "GET,POST,PUT,DELETE" }
      ]
    },
    {
      "source": "/(.*)",
      "headers": [
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "X-Frame-Options", "value": "DENY" }
      ]
    }
  ],

  "redirects": [
    {
      "source": "/old-blog/:slug",
      "destination": "/blog/:slug",
      "permanent": true
    },
    {
      "source": "/twitter",
      "destination": "https://twitter.com/mycompany",
      "permanent": false
    }
  ],

  "rewrites": [
    {
      "source": "/api/external/:path*",
      "destination": "https://external-api.com/:path*"
    },
    {
      "source": "/docs/:match*",
      "destination": "https://docs.example.com/:match*"
    }
  ],

  "cleanUrls": true,
  "trailingSlash": false
}

Serverless Functions

Vercel automatically detects and deploys serverless functions from the api/ or app/api/ folder.

API Route (Next.js App Router)

TSapp/api/users/route.ts
TypeScript
// app/api/users/route.ts
import { NextResponse } from 'next/server'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const id = searchParams.get('id')

  // Your logic
  const users = await fetchUsers(id)

  return NextResponse.json(users)
}

export async function POST(request: Request) {
  const body = await request.json()

  // Your logic
  const user = await createUser(body)

  return NextResponse.json(user, { status: 201 })
}

Standalone Serverless Function

TSapi/hello.ts
TypeScript
// api/hello.ts (standalone, without Next.js)
import type { VercelRequest, VercelResponse } from '@vercel/node'

export default function handler(req: VercelRequest, res: VercelResponse) {
  const { name = 'World' } = req.query

  res.status(200).json({
    message: `Hello ${name}!`
  })
}

Function configuration

TSapi/slow-function.ts
TypeScript
// api/slow-function.ts
export const config = {
  maxDuration: 60, // Max 60 seconds (Pro plan)
  memory: 1024,    // 1GB RAM
}

export default async function handler(req, res) {
  // Long-running operation
}

Edge Functions

Edge Functions run on Cloudflare Workers - ultra fast, global, with minimal cold start.

TSapp/api/geo/route.ts
TypeScript
// app/api/geo/route.ts
export const runtime = 'edge'

export async function GET(request: Request) {
  // Access geo data from request headers
  const country = request.headers.get('x-vercel-ip-country')
  const city = request.headers.get('x-vercel-ip-city')
  const region = request.headers.get('x-vercel-ip-country-region')

  return Response.json({
    country,
    city,
    region,
    greeting: getLocalizedGreeting(country)
  })
}

function getLocalizedGreeting(country: string | null) {
  const greetings: Record<string, string> = {
    PL: 'Cześć!',
    US: 'Hello!',
    DE: 'Hallo!',
    FR: 'Bonjour!',
    ES: 'Hola!'
  }
  return greetings[country || 'US'] || 'Hello!'
}

Edge Middleware

TSmiddleware.ts
TypeScript
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // Check auth token
  const token = request.cookies.get('auth-token')

  if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  // A/B testing
  const bucket = Math.random() < 0.5 ? 'a' : 'b'
  const response = NextResponse.next()
  response.cookies.set('ab-bucket', bucket)

  // Geo-based routing
  const country = request.geo?.country || 'US'
  if (country === 'DE' && request.nextUrl.pathname === '/') {
    return NextResponse.redirect(new URL('/de', request.url))
  }

  return response
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)']
}

Environment Variables

Dashboard

  1. Go to Project Settings -> Environment Variables
  2. Add variables for each environment (Production, Preview, Development)

CLI

Code
Bash
# Add a variable
vercel env add DATABASE_URL production

# List variables
vercel env ls

# Pull variables to .env.local
vercel env pull .env.local

Variable types

Code
TEXT
# Production-only secrets
DATABASE_URL=postgresql://...
API_SECRET=super-secret-key

# Public (available on client-side)
NEXT_PUBLIC_API_URL=https://api.example.com

# Preview-specific
NEXT_PUBLIC_PREVIEW_MODE=true

Domains and SSL

Custom Domain

Code
Bash
# Add a domain via CLI
vercel domains add example.com

# Or in the dashboard: Project Settings → Domains

Automatic SSL

Vercel automatically:

  • Generates an SSL certificate
  • Renews the certificate before expiration
  • Handles redirect from HTTP to HTTPS

Wildcard domains

Code
TEXT
*.example.com → Handles all subdomains

Analytics and Monitoring

Web Analytics

Code
Bash
# Installation
npm i @vercel/analytics
TSapp/layout.tsx
TypeScript
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  )
}

Speed Insights

Code
Bash
npm i @vercel/speed-insights
TSapp/layout.tsx
TypeScript
// app/layout.tsx
import { SpeedInsights } from '@vercel/speed-insights/next'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <SpeedInsights />
      </body>
    </html>
  )
}

Logs

Code
Bash
# Real-time logs
vercel logs --follow

# Production logs
vercel logs --production

# Filtering
vercel logs --since 1h

Cron Jobs

vercel.json
JSON
// vercel.json
{
  "crons": [
    {
      "path": "/api/daily-digest",
      "schedule": "0 8 * * *"
    },
    {
      "path": "/api/cleanup",
      "schedule": "0 0 * * 0"
    }
  ]
}
TSapp/api/daily-digest/route.ts
TypeScript
// app/api/daily-digest/route.ts
export async function GET(request: Request) {
  // Check if this is a cron request
  const authHeader = request.headers.get('authorization')
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return new Response('Unauthorized', { status: 401 })
  }

  // Your cron job logic
  await sendDailyDigestEmails()

  return Response.json({ success: true })
}

Integrations

Database (Vercel Postgres)

Code
Bash
# Create a database in the dashboard or CLI
vercel postgres create my-database

# Connect to the project
vercel link
vercel env pull
TSlib/db.ts
TypeScript
// lib/db.ts
import { sql } from '@vercel/postgres'

export async function getUsers() {
  const { rows } = await sql`SELECT * FROM users`
  return rows
}

Blob Storage

Code
TypeScript
import { put, del, list } from '@vercel/blob'

// Upload
const blob = await put('avatars/user-123.png', file, {
  access: 'public'
})

// Delete
await del(blob.url)

// List
const { blobs } = await list({ prefix: 'avatars/' })

KV (Redis)

Code
TypeScript
import { kv } from '@vercel/kv'

// Set
await kv.set('user:123', { name: 'Alice' })
await kv.set('session:abc', 'data', { ex: 3600 }) // TTL 1h

// Get
const user = await kv.get('user:123')

// Hash
await kv.hset('user:123', { visits: 1 })
await kv.hincrby('user:123', 'visits', 1)

Edge Config

Code
TypeScript
import { get } from '@vercel/edge-config'

// Ultra-fast configuration reading
const featureFlags = await get('feature-flags')

if (featureFlags?.newCheckout) {
  // New checkout
}

Monorepo Support

Turborepo

turbo.json
JSON
// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {},
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
Code
Bash
# Structure
apps/
├── web/           # Next.js app
├── docs/          # Documentation site
└── admin/         # Admin panel
packages/
├── ui/            # Shared components
├── config/        # Shared config
└── database/      # Prisma client

Vercel Monorepo Settings

In the dashboard: Project Settings -> Root Directory

  • apps/web for the web project
  • apps/docs for documentation

CI/CD Customization

Ignore Build Step

vercel-ignore-build-step.sh
Bash
# vercel-ignore-build-step.sh
#!/bin/bash

# If only docs were changed, skip the build
if git diff --quiet HEAD^ HEAD -- docs/; then
  echo "No changes in source code. Skipping build."
  exit 0
fi

exit 1
vercel.json
JSON
// vercel.json
{
  "ignoreCommand": "bash vercel-ignore-build-step.sh"
}

Custom Build

vercel.json
JSON
// vercel.json
{
  "buildCommand": "npm run build:production",
  "installCommand": "npm ci --legacy-peer-deps",
  "framework": null
}

Pricing (2025)

PlanPriceBandwidthServerlessTeam
HobbyFree100GB100GB-hrs1 user
Pro$20/user/mo1TB1000GB-hrsUnlimited
EnterpriseCustomUnlimitedUnlimitedCustom

Hobby Limits

  • 100GB bandwidth/month
  • 100 deployments/day
  • Serverless function timeout: 10s
  • Edge function timeout: 30s
  • No team features

Pro Features

  • 1TB bandwidth
  • Serverless timeout: 60s
  • Password protection
  • Team collaboration
  • Priority support
  • Advanced analytics

Vercel vs Alternatives

AspectVercelNetlifyRailwayAWS Amplify
Next.js SupportNativeAdapterAdapterAdapter
Edge FunctionsYesYesNoYes
Preview DeploysYesYesYesYes
PricingPer-userPer-siteUsage-basedUsage-based
DatabasePostgres, KVNonePostgresDynamoDB
Best forNext.jsStatic/JAMstackFull-stackAWS ecosystem

Best Practices

1. Optimize build time

JSnext.config.js
JavaScript
// next.config.js
module.exports = {
  // Use standalone output for smaller deployments
  output: 'standalone',

  // Disable source maps in production
  productionBrowserSourceMaps: false,
}

2. Cache dependencies

Vercel automatically caches node_modules, but you can control this:

vercel.json
JSON
// vercel.json
{
  "build": {
    "env": {
      "VERCEL_FORCE_NO_BUILD_CACHE": "1"
    }
  }
}

3. Use regions

Code
TypeScript
// Specify a region for functions
export const config = {
  regions: ['iad1', 'cdg1'] // US East, France
}

4. Monitor usage

  • Check the dashboard regularly
  • Set alerts for approaching limits
  • Analyze functions consuming the most resources

Troubleshooting

Build fails

Code
Bash
# Check local builds
npm run build

# Check logs
vercel logs --follow

Function timeout

Code
TypeScript
// Increase timeout (Pro plan required)
export const config = {
  maxDuration: 60
}

// Or use Edge for faster cold starts
export const runtime = 'edge'

Cache issues

Code
Bash
# Force rebuild without cache
vercel --force

# Or in the dashboard: Redeploy with cleared cache

FAQ

Can I use Vercel with frameworks other than Next.js?

Yes! Vercel supports: React, Vue, Nuxt, Svelte, SvelteKit, Astro, Remix, Gatsby, Angular, and many others.

How do I migrate from another hosting provider?

  1. Connect your repo to Vercel
  2. Configure environment variables
  3. Add a custom domain
  4. Change DNS to Vercel

Is Vercel expensive?

The free tier is very generous for personal projects. Pro ($20/user/mo) is the standard for commercial projects. Enterprise is for large companies.

Can I self-host Next.js instead of Vercel?

Yes, Next.js can be hosted on any Node.js server. However, Vercel offers the best integration and many features out of the box.

Summary

Vercel is the best platform for Next.js projects and modern frontend development:

  • Zero-config - Deploy in seconds
  • Preview Deployments - Test every PR
  • Edge Network - Globally fast
  • Serverless - No server management
  • Integrations - Database, blob, KV, analytics