Home / Notebooks / Deployment & DevOps
Deployment & DevOps
intermediate

Vercel Essentials

Complete guide to deploying production-ready applications with custom domains on Vercel

April 20, 2026
Updated regularly

Vercel Essentials

Complete guide to deploying production-ready applications with custom domains on Vercel.

What is Vercel?

Vercel is a cloud platform for static sites and serverless functions that enables developers to deploy instantly and scale automatically.

Key Features:

  • Zero-configuration deployments
  • Automatic HTTPS and CDN
  • Git integration (auto-deploy on push)
  • Preview deployments for every PR
  • Edge network (low latency globally)
  • Serverless functions
  • Built-in analytics and monitoring
  • Custom domains with SSL
  • Best For:

  • Next.js applications (created by Vercel)
  • React, Vue, Svelte, Angular apps
  • Static sites (HTML, CSS, JS)
  • JAMstack applications
  • API endpoints (serverless functions)
  • Prerequisites

    Requirements

    Before starting, ensure you have:

  • GitHub, GitLab, or Bitbucket account
  • Node.js 18+ installed (for local development)
  • Git installed
  • Domain name (optional, for custom domain setup)
  • Installation

    Install Vercel CLI

    # ========== Install Globally ==========
    npm install -g vercel
    
    # ========== Verify Installation ==========
    vercel --version
    
    # ========== Login to Vercel ==========
    vercel login
    
    # Follow the prompts:
    # 1. Choose authentication method (GitHub, GitLab, Email)
    # 2. Verify in browser
    # 3. Return to terminal
    
    Expected Output:
    > Success! GitHub authentication complete.
    > Email: your.email@example.com
    > Connected to: YourName
    

    Quick Start

    Deploy Your First Project

    Step 1: Navigate to Your Project

    # Go to your project directory
    cd /path/to/your/project
    
    # Example project structure:
    # myapp/
    # ├── package.json
    # ├── next.config.js
    # └── src/
    #     └── ...
    

    Step 2: Deploy

    # ========== One-Command Deploy ==========
    vercel
    
    # This will:
    # 1. Detect your framework (Next.js, React, etc.)
    # 2. Configure build settings automatically
    # 3. Upload and build your project
    # 4. Provide preview URL
    
    Interactive Setup:
    Vercel CLI 33.0.0
    ? Set up and deploy "~/myapp"? [Y/n] y
    ? Which scope do you want to deploy to? YourName
    ? Link to existing project? [y/N] n
    ? What's your project's name? myapp
    ? In which directory is your code located? ./
    Auto-detected Project Settings (Next.js):
    - Build Command: next build
    - Output Directory: .next
    - Development Command: next dev
    ? Want to override the settings? [y/N] n
    
    🔗 Linked to yourname/myapp
    🔍 Inspect: https://vercel.com/yourname/myapp/inspect
    ✅ Production: https://myapp.vercel.app [copied to clipboard]
    

    Step 3: Visit Your Site

    # Your app is now live at:
    # https://myapp.vercel.app
    
    # Preview the deployment
    vercel open
    

    Git Integration

    Connect Repository

    Via Vercel Dashboard:

  • Go to Vercel Dashboard
  • - Visit https://vercel.com/dashboard - Click "Add New..." → "Project"
  • Import Git Repository
  • - Select GitHub/GitLab/Bitbucket - Authorize Vercel - Choose repository
  • Configure Project
  •    Framework Preset: Next.js (auto-detected)
       Root Directory: ./
       Build Command: npm run build (auto-filled)
       Output Directory: .next (auto-filled)
       Install Command: npm install (auto-filled)
       
  • Deploy
  • - Click "Deploy" - Wait for build to complete - Get production URL

    Automatic Deployments

    Production Deployment:
    # Every push to main/master branch triggers production deployment
    git add .
    git commit -m "Update homepage"
    git push origin main
    
    # Vercel automatically:
    # ✓ Detects push
    # ✓ Builds project
    # ✓ Deploys to production
    # ✓ Updates https://myapp.vercel.app
    
    Preview Deployments:
    # Every push to other branches creates preview deployment
    git checkout -b feature/new-header
    git add .
    git commit -m "Add new header"
    git push origin feature/new-header
    
    # Vercel creates unique preview URL:
    # https://myapp-git-feature-new-header.vercel.app
    
    # Also comments on PR with preview link
    

    Environment Variables

    Managing Environment Variables

    Via Vercel Dashboard:

  • Go to Project Settings
  • Navigate to "Environment Variables"
  • Add variables for different environments
  • Via CLI:

    # ========== Add Environment Variable ==========
    vercel env add DATABASE_URL
    
    # Interactive prompts:
    ? What's the value of DATABASE_URL? postgres://...
    ? Add to Development, Preview, and Production? Production
    
    # ========== Add Multiple Variables ==========
    vercel env add API_KEY
    vercel env add STRIPE_SECRET_KEY
    vercel env add REDIS_URL
    
    # ========== Pull Environment Variables ==========
    # Download env vars to local .env file
    vercel env pull .env.local
    
    # ========== List Environment Variables ==========
    vercel env ls
    

    Environment-Specific Variables

    # ========== Development Only ==========
    vercel env add DEV_API_URL
    ? Add to which environment? Development
    
    # ========== Preview Only ==========
    vercel env add STAGING_DATABASE
    ? Add to which environment? Preview
    
    # ========== Production Only ==========
    vercel env add PROD_API_KEY
    ? Add to which environment? Production
    
    # ========== All Environments ==========
    vercel env add ANALYTICS_ID
    ? Add to which environment? Development, Preview, Production
    

    Using in Code

    Next.js Example:

    // ========== Server-side (API Routes, getServerSideProps) ==========
    // Access with process.env
    export default function handler(req, res) {
      const apiKey = process.env.API_KEY;
      const dbUrl = process.env.DATABASE_URL;
      
      // Use variables...
    }
    
    // ========== Client-side ==========
    // Must be prefixed with NEXT_PUBLIC_
    export default function Component() {
      const publicKey = process.env.NEXT_PUBLIC_STRIPE_KEY;
      
      return <div>{/* Use public key */}</div>;
    }
    

    Environment Variables File Structure:

    # .env.local (development)
    DATABASE_URL=localhost:5432
    API_KEY=dev_key_123
    NEXT_PUBLIC_API_URL=http://localhost:3000
    
    # .env.production (production - set in Vercel dashboard)
    DATABASE_URL=production-db-url
    API_KEY=prod_key_xyz
    NEXT_PUBLIC_API_URL=https://api.yourdomain.com
    

    Custom Domain Setup

    Add Custom Domain

    Method 1: Via Dashboard

  • Go to Project Settings
  • - Open your project in Vercel Dashboard - Click "Settings" → "Domains"
  • Add Domain
  • - Click "Add" - Enter your domain: yourdomain.com - Click "Add"
  • Configure DNS
  • - Vercel shows DNS records you need to add - Copy the records

    Method 2: Via CLI

    # ========== Add Domain ==========
    vercel domains add yourdomain.com
    
    # ========== Add with Alias ==========
    vercel alias set myapp.vercel.app yourdomain.com
    

    DNS Configuration

    Option A: Vercel Nameservers (Recommended)

    Set these nameservers at your domain registrar:
    ns1.vercel-dns.com
    ns2.vercel-dns.com
    

    Benefits:

  • ✅ Automatic SSL certificate
  • ✅ Automatic DNS configuration
  • ✅ Optimal performance
  • ✅ No manual DNS records needed
  • Option B: Custom DNS (A/CNAME Records)

    For Root Domain (yourdomain.com):
    Type: A
    Name: @
    Value: 76.76.21.21
    TTL: 3600
    
    For Subdomain (www.yourdomain.com):
    Type: CNAME
    Name: www
    Value: cname.vercel-dns.com
    TTL: 3600
    
    For Both (Root + www):
    # Root domain
    Type: A
    Name: @
    Value: 76.76.21.21
    
    # WWW subdomain
    Type: CNAME
    Name: www
    Value: cname.vercel-dns.com
    

    SSL Certificate

    Automatic SSL:

  • Vercel automatically provisions SSL certificates
  • Uses Let's Encrypt
  • Auto-renewal every 90 days
  • No configuration needed
  • Verify SSL:
    # Check certificate status
    vercel certs ls
    
    # View certificate details
    vercel certs inspect yourdomain.com
    

    Multiple Domains

    # ========== Add Multiple Domains ==========
    vercel domains add yourdomain.com
    vercel domains add www.yourdomain.com
    vercel domains add app.yourdomain.com
    
    # ========== Set Production Domain ==========
    vercel alias set myapp.vercel.app yourdomain.com --prod
    
    # ========== Redirect www to non-www ==========
    # Add redirect in vercel.json:
    
    vercel.json:
    {
      "redirects": [
        {
          "source": "www.yourdomain.com/:path*",
          "destination": "https://yourdomain.com/:path*",
          "permanent": true
        }
      ]
    }
    

    Configuration

    vercel.json

    Basic Configuration:

    {
      "version": 2,
      "name": "myapp",
      "builds": [
        {
          "src": "package.json",
          "use": "@vercel/next"
        }
      ]
    }
    

    Build Settings

    Custom Build Configuration:

    {
      "buildCommand": "npm run build",
      "devCommand": "npm run dev",
      "installCommand": "npm install",
      "framework": "nextjs",
      "outputDirectory": ".next"
    }
    

    Redirects and Rewrites

    Redirects (301/302):

    {
      "redirects": [
        {
          "source": "/old-page",
          "destination": "/new-page",
          "permanent": true
        },
        {
          "source": "/blog/:slug",
          "destination": "/news/:slug",
          "permanent": false
        },
        {
          "source": "/old-site/:path*",
          "destination": "https://newsitedomain.com/:path*",
          "permanent": true
        }
      ]
    }
    

    Rewrites (Proxying):

    {
      "rewrites": [
        {
          "source": "/api/:path*",
          "destination": "https://api.external.com/:path*"
        },
        {
          "source": "/blog",
          "destination": "https://blog.yourdomain.com"
        }
      ]
    }
    

    Headers

    Custom Headers:

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

    Caching

    Cache-Control Headers:

    {
      "headers": [
        {
          "source": "/static/(.*)",
          "headers": [
            {
              "key": "Cache-Control",
              "value": "public, max-age=31536000, immutable"
            }
          ]
        },
        {
          "source": "/_next/static/(.*)",
          "headers": [
            {
              "key": "Cache-Control",
              "value": "public, max-age=31536000, immutable"
            }
          ]
        }
      ]
    }
    

    Serverless Functions

    Creating API Routes

    Next.js API Routes (Automatic):

    // pages/api/hello.js
    export default function handler(req, res) {
      // Automatically deployed as serverless function
      res.status(200).json({ message: 'Hello from Vercel!' });
    }
    
    // Available at: https://yourdomain.com/api/hello
    

    Standalone Serverless Function:

    // api/user.js
    module.exports = (req, res) => {
      const { userId } = req.query;
      
      // Database query...
      
      res.status(200).json({
        userId,
        name: 'John Doe'
      });
    }
    
    // Available at: https://yourdomain.com/api/user?userId=123
    

    Function Configuration

    Timeout and Memory:

    {
      "functions": {
        "api/heavy-computation.js": {
          "memory": 3008,
          "maxDuration": 60
        },
        "api/*.js": {
          "memory": 1024,
          "maxDuration": 10
        }
      }
    }
    

    Memory Options: 128, 256, 512, 1024, 3008 MB Max Duration: 10s (Hobby), 60s (Pro), 900s (Enterprise)

    Performance Optimization

    Image Optimization

    Next.js Image Component:

    import Image from 'next/image';
    
    export default function Component() {
      return (
        <Image
          src="/hero.jpg"
          alt="Hero"
          width={1200}
          height={600}
          priority  // Load immediately
          quality={90}  // Image quality (1-100)
        />
      );
    }
    
    // Vercel automatically:
    // ✓ Optimizes image format (WebP, AVIF)
    // ✓ Resizes for device
    // ✓ Lazy loads by default
    // ✓ Serves from Edge CDN
    

    Image Optimization Config:

    // next.config.js
    module.exports = {
      images: {
        domains: ['cdn.example.com', 'images.unsplash.com'],
        formats: ['image/webp', 'image/avif'],
        deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
        imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
      }
    };
    

    Edge Functions

    Use Edge Runtime for Ultra-Low Latency:

    // pages/api/edge.js
    export const config = {
      runtime: 'edge',  // Run on Edge (not serverless)
    };
    
    export default async function handler(req) {
      return new Response(
        JSON.stringify({ message: 'Hello from the Edge!' }),
        {
          status: 200,
          headers: {
            'Content-Type': 'application/json',
          },
        }
      );
    }
    
    // Benefits:
    // ✓ <10ms cold start
    // ✓ Runs globally at the edge
    // ✓ Lower cost
    

    Static Generation

    Optimize Build with ISR (Incremental Static Regeneration):

    // pages/blog/[slug].js
    export async function getStaticProps({ params }) {
      const post = await getPost(params.slug);
      
      return {
        props: { post },
        revalidate: 60,  // Regenerate page every 60 seconds
      };
    }
    
    export async function getStaticPaths() {
      return {
        paths: [],
        fallback: 'blocking',  // Generate on first request
      };
    }
    
    // Benefits:
    // ✓ Fast page loads (pre-rendered)
    // ✓ Automatic updates
    // ✓ Reduced serverless costs
    

    Deployment Workflows

    Production Deployment

    Manual Production Deploy:

    # ========== Deploy to Production ==========
    vercel --prod
    
    # ========== Deploy with Custom Domain ==========
    vercel --prod --target production
    
    # ========== View Deployment Logs ==========
    vercel logs myapp.vercel.app
    
    # ========== Inspect Deployment ==========
    vercel inspect https://myapp-abc123.vercel.app
    

    Preview Deployments

    Create Preview from Branch:

    # ========== Deploy Current Branch as Preview ==========
    vercel
    
    # Gets unique URL like:
    # https://myapp-git-feature-branch-username.vercel.app
    
    # ========== Deploy Specific Branch ==========
    git checkout feature/new-design
    vercel
    
    # ========== Share Preview ==========
    vercel ls  # List deployments
    vercel open  # Open latest in browser
    

    Rollback

    Rollback to Previous Deployment:

    # ========== List Recent Deployments ==========
    vercel ls
    
    # Output:
    # Age  Deployment              Status   Duration
    # 2m   myapp-abc123.vercel.app Ready    1m 23s
    # 1h   myapp-def456.vercel.app Ready    1m 15s
    # 2h   myapp-ghi789.vercel.app Ready    1m 30s
    
    # ========== Promote Previous Deployment ==========
    vercel alias set myapp-def456.vercel.app yourdomain.com --prod
    
    # ========== Instant Rollback ==========
    vercel rollback https://myapp-def456.vercel.app
    

    CI/CD Integration

    GitHub Actions

    Deploy on Push:

    # .github/workflows/deploy.yml
    name: Deploy to Vercel
    
    on:
      push:
        branches: [main]
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          
          - name: Setup Node.js
            uses: actions/setup-node@v3
            with:
              node-version: '18'
          
          - name: Install Vercel CLI
            run: npm install -g vercel
          
          - name: Pull Vercel Environment
            run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
          
          - name: Build Project
            run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
          
          - name: Deploy to Vercel
            run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
    

    Required Secrets:

  • VERCEL_TOKEN - Get from Vercel Dashboard → Settings → Tokens
  • VERCEL_ORG_ID - Found in .vercel/project.json
  • VERCEL_PROJECT_ID - Found in .vercel/project.json
  • GitLab CI

    # .gitlab-ci.yml
    deploy:
      stage: deploy
      image: node:18
      script:
        - npm install -g vercel
        - vercel pull --yes --environment=production --token=$VERCEL_TOKEN
        - vercel build --prod --token=$VERCEL_TOKEN
        - vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN
      only:
        - main
    

    Monitoring and Analytics

    Vercel Analytics

    Enable Analytics:

    # Install package
    npm install @vercel/analytics
    
    # Add to your app
    
    // pages/_app.js
    import { Analytics } from '@vercel/analytics/react';
    
    export default function App({ Component, pageProps }) {
      return (
        <>
          <Component {...pageProps} />
          <Analytics />
        </>
      );
    }
    

    View Analytics:

  • Go to Vercel Dashboard
  • Select your project
  • Click "Analytics" tab
  • Metrics Available:

  • Page views
  • Unique visitors
  • Top pages
  • Referrers
  • Devices and browsers
  • Speed Insights

    # Install Speed Insights
    npm install @vercel/speed-insights
    
    # Add to your app
    
    // pages/_app.js
    import { SpeedInsights } from '@vercel/speed-insights/next';
    
    export default function App({ Component, pageProps }) {
      return (
        <>
          <Component {...pageProps} />
          <SpeedInsights />
        </>
      );
    }
    

    Real User Metrics (RUM):

  • First Contentful Paint (FCP)
  • Largest Contentful Paint (LCP)
  • First Input Delay (FID)
  • Cumulative Layout Shift (CLS)
  • Time to First Byte (TTFB)
  • Log Drains

    Stream Logs to External Service:

    # ========== Add Log Drain ==========
    vercel log-drain add https://logs.example.com
    
    # Supported services:
    # - Datadog
    # - LogDNA
    # - Logtail
    # - Splunk
    # - Custom HTTP endpoint
    

    Security

    Environment Protection

    Password Protection:

    # Via Dashboard:
    # 1. Go to Project Settings
    # 2. Click "Deployment Protection"
    # 3. Enable "Vercel Authentication"
    # 4. Or set password for deployment
    

    Restrict Preview Deployments:

    {
      "github": {
        "silent": true,
        "autoJobCancelation": true
      }
    }
    

    Security Headers

    Production-Ready Security Headers:

    {
      "headers": [
        {
          "source": "/(.*)",
          "headers": [
            {
              "key": "X-Frame-Options",
              "value": "DENY"
            },
            {
              "key": "X-Content-Type-Options",
              "value": "nosniff"
            },
            {
              "key": "X-XSS-Protection",
              "value": "1; mode=block"
            },
            {
              "key": "Referrer-Policy",
              "value": "strict-origin-when-cross-origin"
            },
            {
              "key": "Permissions-Policy",
              "value": "geolocation=(), microphone=(), camera=()"
            },
            {
              "key": "Strict-Transport-Security",
              "value": "max-age=31536000; includeSubDomains"
            },
            {
              "key": "Content-Security-Policy",
              "value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
            }
          ]
        }
      ]
    }
    

    Troubleshooting

    Common Issues

    Build Failures:

    # ========== View Build Logs ==========
    vercel logs https://myapp-abc123.vercel.app
    
    # ========== Check Build Settings ==========
    vercel inspect https://myapp-abc123.vercel.app
    
    # Common fixes:
    # 1. Verify Node version in package.json
    {
      "engines": {
        "node": ">=18.0.0"
      }
    }
    
    # 2. Clear build cache
    vercel --force
    
    # 3. Check environment variables
    vercel env ls
    

    Domain Not Working:

    # ========== Verify DNS Configuration ==========
    nslookup yourdomain.com
    
    # ========== Check Domain Status ==========
    vercel domains ls
    
    # ========== Remove and Re-add Domain ==========
    vercel domains rm yourdomain.com
    vercel domains add yourdomain.com
    
    # ========== Wait for DNS Propagation ==========
    # Can take up to 48 hours (usually <1 hour)
    # Check status: https://www.whatsmydns.net/
    

    Function Timeout:

    # Increase timeout in vercel.json
    {
      "functions": {
        "api/slow-function.js": {
          "maxDuration": 30  // Increase to 30s
        }
      }
    }
    
    # Or upgrade plan for longer timeouts:
    # Hobby: 10s
    # Pro: 60s
    # Enterprise: 900s
    

    Large Bundle Size:

    # Analyze bundle
    npm install -g @next/bundle-analyzer
    
    # In next.config.js:
    const withBundleAnalyzer = require('@next/bundle-analyzer')({
      enabled: process.env.ANALYZE === 'true',
    });
    
    module.exports = withBundleAnalyzer({
      // config
    });
    
    # Run analysis
    ANALYZE=true npm run build
    
    # Common fixes:
    # 1. Use dynamic imports
    const Component = dynamic(() => import('./Component'));
    
    # 2. Remove unused dependencies
    npm uninstall unused-package
    
    # 3. Use tree-shaking
    # Import only what you need
    import { specific } from 'library';  // Good
    import * as library from 'library';  // Bad
    

    Best Practices

    Production Checklist

    Before Going Live:

  • [ ] Environment Variables Set
  •   vercel env ls
      # Verify all production secrets are set
      
  • [ ] Custom Domain Configured
  •   vercel domains ls
      # Ensure SSL is active
      
  • [ ] Build Optimizations
  • - Enable image optimization - Configure caching headers - Minimize bundle size - Use static generation where possible
  • [ ] Security Headers
  • - Add CSP, HSTS, X-Frame-Options - Enable rate limiting for APIs - Use environment-based secrets
  • [ ] Monitoring Enabled
  • - Install Vercel Analytics - Add Speed Insights - Configure log drains
  • [ ] Error Handling
  • - Custom 404 page - Custom 500 page - Error boundaries in React
  • [ ] Testing
  • - Test preview deployment - Check mobile responsiveness - Verify all API endpoints - Test from different regions

    Performance Tips

    1. Use Edge Functions for APIs
    export const config = { runtime: 'edge' };
    
    2. Optimize Images
    import Image from 'next/image';
    // Always use Next.js Image component
    
    3. Enable ISR
    export async function getStaticProps() {
      return {
        props: {},
        revalidate: 60,  // Regenerate every 60s
      };
    }
    
    4. Configure Caching
    {
      "headers": [
        {
          "source": "/static/(.*)",
          "headers": [
            { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
          ]
        }
      ]
    }
    
    5. Use Compression
    // next.config.js
    module.exports = {
      compress: true,  // Enable gzip compression
    };
    

    Resources

  • Official Docs: https://vercel.com/docs
  • CLI Reference: https://vercel.com/docs/cli
  • Templates: https://vercel.com/templates
  • Discord Community: https://vercel.com/discord
  • Status Page: https://www.vercel-status.com/
  • Quick Reference Card

    # ========== Deployment ==========
    vercel                          # Deploy to preview
    vercel --prod                   # Deploy to production
    vercel --force                  # Force rebuild
    
    # ========== Domains ==========
    vercel domains add example.com  # Add custom domain
    vercel domains ls               # List domains
    vercel alias set old.vercel.app example.com
    
    # ========== Environment Variables ==========
    vercel env add VAR_NAME         # Add env variable
    vercel env ls                   # List variables
    vercel env pull                 # Download to .env.local
    
    # ========== Logs & Monitoring ==========
    vercel logs                     # View logs
    vercel inspect URL              # Inspect deployment
    vercel ls                       # List deployments
    
    # ========== Management ==========
    vercel rollback URL             # Rollback deployment
    vercel rm DEPLOYMENT            # Remove deployment
    vercel projects ls              # List all projects
    

    Next Steps

  • Deploy your first project with vercel
  • Add a custom domain
  • Set up environment variables
  • Configure caching and headers
  • Enable analytics and monitoring
  • Set up CI/CD pipeline
  • ---

    Last Updated: 2026-04-20 Vercel CLI Version: 33+ Difficulty: Intermediate

    Topics

    VercelDeploymentDevOpsNext.jsCustom Domain

    Found This Helpful?

    If you have questions or suggestions for improving these notes, I'd love to hear from you.