Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    liauw-media

    vercel-deployment

    liauw-media/vercel-deployment
    DevOps
    1
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Vercel deployment patterns and best practices. Use when deploying frontend applications, configuring edge functions, setting up preview deployments, or optimizing Next.js applications.

    SKILL.md

    Vercel Deployment

    Comprehensive guide for deploying and optimizing applications on Vercel's edge platform.

    When to Use

    • Deploying Next.js, React, Vue, or static sites
    • Setting up preview deployments for PRs
    • Configuring edge and serverless functions
    • Optimizing performance with edge caching
    • Managing environment variables and secrets
    • Setting up custom domains and SSL

    Core Concepts

    Vercel Architecture

    ┌─────────────────────────────────────────────────────────────────┐
    │                        Vercel Edge Network                      │
    │                                                                 │
    │  ┌─────────────────────────────────────────────────────────┐   │
    │  │                    Edge Middleware                       │   │
    │  │              (Runs at edge, <1ms latency)                │   │
    │  └─────────────────────────────────────────────────────────┘   │
    │                              │                                  │
    │         ┌────────────────────┼────────────────────┐            │
    │         │                    │                    │            │
    │         ▼                    ▼                    ▼            │
    │  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐      │
    │  │   Static    │     │  Serverless │     │    Edge     │      │
    │  │   Assets    │     │  Functions  │     │  Functions  │      │
    │  │   (CDN)     │     │  (Node.js)  │     │  (V8)       │      │
    │  └─────────────┘     └─────────────┘     └─────────────┘      │
    │                                                                 │
    └─────────────────────────────────────────────────────────────────┘
    

    Function Types

    Type Runtime Cold Start Use Case
    Serverless Node.js 250ms API routes, SSR
    Edge V8 <1ms Auth, redirects, A/B
    Static N/A 0 HTML, CSS, JS, images

    Project Configuration

    vercel.json

    {
      "$schema": "https://openapi.vercel.sh/vercel.json",
      "framework": "nextjs",
      "buildCommand": "npm run build",
      "outputDirectory": ".next",
      "installCommand": "npm ci",
      "devCommand": "npm run dev",
    
      "regions": ["iad1", "sfo1", "cdg1"],
    
      "functions": {
        "api/**/*.ts": {
          "memory": 1024,
          "maxDuration": 30
        },
        "api/heavy-task.ts": {
          "memory": 3008,
          "maxDuration": 60
        }
      },
    
      "crons": [
        {
          "path": "/api/cron/daily-cleanup",
          "schedule": "0 0 * * *"
        },
        {
          "path": "/api/cron/hourly-sync",
          "schedule": "0 * * * *"
        }
      ],
    
      "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" },
            { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
          ]
        }
      ],
    
      "redirects": [
        {
          "source": "/old-page",
          "destination": "/new-page",
          "permanent": true
        },
        {
          "source": "/blog/:slug",
          "destination": "/posts/:slug",
          "permanent": false
        }
      ],
    
      "rewrites": [
        {
          "source": "/api/v1/:path*",
          "destination": "https://api.example.com/:path*"
        }
      ]
    }
    

    next.config.js (Next.js)

    /** @type {import('next').NextConfig} */
    const nextConfig = {
      // Output configuration
      output: 'standalone',
    
      // Image optimization
      images: {
        remotePatterns: [
          {
            protocol: 'https',
            hostname: 'images.example.com',
          },
        ],
        formats: ['image/avif', 'image/webp'],
      },
    
      // Headers
      async headers() {
        return [
          {
            source: '/:path*',
            headers: [
              {
                key: 'X-DNS-Prefetch-Control',
                value: 'on',
              },
              {
                key: 'Strict-Transport-Security',
                value: 'max-age=63072000; includeSubDomains; preload',
              },
            ],
          },
        ];
      },
    
      // Rewrites for API proxying
      async rewrites() {
        return [
          {
            source: '/api/external/:path*',
            destination: `${process.env.API_URL}/:path*`,
          },
        ];
      },
    
      // Experimental features
      experimental: {
        serverActions: {
          bodySizeLimit: '2mb',
        },
      },
    };
    
    module.exports = nextConfig;
    

    Edge Functions

    Edge Middleware

    // middleware.ts
    import { NextResponse } from 'next/server';
    import type { NextRequest } from 'next/server';
    
    export const config = {
      matcher: [
        // Match all paths except static files
        '/((?!_next/static|_next/image|favicon.ico).*)',
      ],
    };
    
    export function middleware(request: NextRequest) {
      const { pathname, searchParams } = request.nextUrl;
    
      // Authentication check
      const token = request.cookies.get('token')?.value;
      if (pathname.startsWith('/dashboard') && !token) {
        return NextResponse.redirect(new URL('/login', request.url));
      }
    
      // Geolocation-based routing
      const country = request.geo?.country || 'US';
      if (pathname === '/' && country === 'CN') {
        return NextResponse.redirect(new URL('/cn', request.url));
      }
    
      // A/B Testing
      const bucket = request.cookies.get('ab-bucket')?.value;
      if (!bucket) {
        const newBucket = Math.random() < 0.5 ? 'control' : 'experiment';
        const response = NextResponse.next();
        response.cookies.set('ab-bucket', newBucket, {
          maxAge: 60 * 60 * 24 * 30, // 30 days
        });
        return response;
      }
    
      // Rate limiting header
      const response = NextResponse.next();
      response.headers.set('X-Request-Country', country);
    
      return response;
    }
    

    Edge API Route

    // app/api/edge-function/route.ts
    import { NextRequest } from 'next/server';
    
    export const runtime = 'edge';
    export const preferredRegion = ['iad1', 'sfo1', 'cdg1'];
    
    export async function GET(request: NextRequest) {
      const { searchParams } = new URL(request.url);
      const name = searchParams.get('name') || 'World';
    
      // Access edge-specific APIs
      const country = request.geo?.country;
      const city = request.geo?.city;
    
      return Response.json({
        message: `Hello, ${name}!`,
        location: { country, city },
        timestamp: Date.now(),
      });
    }
    
    export async function POST(request: NextRequest) {
      const body = await request.json();
    
      // Process at the edge
      return Response.json({
        received: body,
        processedAt: new Date().toISOString(),
      });
    }
    

    Serverless Functions

    API Route (App Router)

    // app/api/users/route.ts
    import { NextRequest, NextResponse } from 'next/server';
    import { db } from '@/lib/db';
    
    export const dynamic = 'force-dynamic';
    export const maxDuration = 30;
    
    export async function GET(request: NextRequest) {
      try {
        const { searchParams } = new URL(request.url);
        const page = parseInt(searchParams.get('page') || '1');
        const limit = parseInt(searchParams.get('limit') || '10');
    
        const users = await db.user.findMany({
          skip: (page - 1) * limit,
          take: limit,
          orderBy: { createdAt: 'desc' },
        });
    
        return NextResponse.json({ users, page, limit });
      } catch (error) {
        console.error('Error fetching users:', error);
        return NextResponse.json(
          { error: 'Internal server error' },
          { status: 500 }
        );
      }
    }
    
    export async function POST(request: NextRequest) {
      try {
        const body = await request.json();
    
        const user = await db.user.create({
          data: {
            email: body.email,
            name: body.name,
          },
        });
    
        return NextResponse.json(user, { status: 201 });
      } catch (error) {
        console.error('Error creating user:', error);
        return NextResponse.json(
          { error: 'Failed to create user' },
          { status: 500 }
        );
      }
    }
    

    Dynamic Route Handler

    // app/api/users/[id]/route.ts
    import { NextRequest, NextResponse } from 'next/server';
    import { db } from '@/lib/db';
    
    export async function GET(
      request: NextRequest,
      { params }: { params: { id: string } }
    ) {
      const user = await db.user.findUnique({
        where: { id: params.id },
      });
    
      if (!user) {
        return NextResponse.json(
          { error: 'User not found' },
          { status: 404 }
        );
      }
    
      return NextResponse.json(user);
    }
    
    export async function PUT(
      request: NextRequest,
      { params }: { params: { id: string } }
    ) {
      const body = await request.json();
    
      const user = await db.user.update({
        where: { id: params.id },
        data: body,
      });
    
      return NextResponse.json(user);
    }
    
    export async function DELETE(
      request: NextRequest,
      { params }: { params: { id: string } }
    ) {
      await db.user.delete({
        where: { id: params.id },
      });
    
      return new NextResponse(null, { status: 204 });
    }
    

    Environment Variables

    Variable Types

    Type Prefix Accessible
    Server None Server only
    Public NEXT_PUBLIC_ Client & Server
    System VERCEL_ Auto-provided

    Configuration

    # .env.local (local development)
    DATABASE_URL="postgresql://..."
    API_SECRET="secret-key"
    NEXT_PUBLIC_APP_URL="http://localhost:3000"
    
    # Production (set in Vercel dashboard)
    DATABASE_URL="postgresql://prod..."
    API_SECRET="prod-secret"
    NEXT_PUBLIC_APP_URL="https://myapp.com"
    

    Environment-Specific Variables

    // Access in code
    const dbUrl = process.env.DATABASE_URL;
    const appUrl = process.env.NEXT_PUBLIC_APP_URL;
    
    // Vercel system variables
    const deploymentUrl = process.env.VERCEL_URL;
    const environment = process.env.VERCEL_ENV; // production, preview, development
    const gitCommit = process.env.VERCEL_GIT_COMMIT_SHA;
    const gitBranch = process.env.VERCEL_GIT_COMMIT_REF;
    

    Preview Deployments

    Branch Configuration

    // vercel.json
    {
      "git": {
        "deploymentEnabled": {
          "main": true,
          "staging": true,
          "feature/*": true
        }
      }
    }
    

    Preview Environment Variables

    # Set different values for preview deployments
    # In Vercel Dashboard: Settings > Environment Variables
    
    # Production
    DATABASE_URL=postgresql://prod-db/app
    
    # Preview (automatically used for PR deployments)
    DATABASE_URL=postgresql://staging-db/app
    
    # Development
    DATABASE_URL=postgresql://dev-db/app
    

    Comment on PR

    # .github/workflows/vercel-preview.yml
    name: Vercel Preview
    on:
      pull_request:
        types: [opened, synchronize]
    
    jobs:
      preview:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
    
          - name: Deploy to Vercel
            id: deploy
            uses: amondnet/vercel-action@v25
            with:
              vercel-token: ${{ secrets.VERCEL_TOKEN }}
              vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
              vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
    
          - name: Comment 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 to: ${{ steps.deploy.outputs.preview-url }}`
                })
    

    Caching & Performance

    Cache Headers

    // app/api/data/route.ts
    export async function GET() {
      const data = await fetchData();
    
      return Response.json(data, {
        headers: {
          // Cache for 1 hour, revalidate in background
          'Cache-Control': 's-maxage=3600, stale-while-revalidate=86400',
        },
      });
    }
    

    ISR (Incremental Static Regeneration)

    // app/posts/[slug]/page.tsx
    export const revalidate = 3600; // Revalidate every hour
    
    export async function generateStaticParams() {
      const posts = await getPosts();
      return posts.map((post) => ({ slug: post.slug }));
    }
    
    export default async function PostPage({ params }: { params: { slug: string } }) {
      const post = await getPost(params.slug);
      return <Post post={post} />;
    }
    

    On-Demand Revalidation

    // app/api/revalidate/route.ts
    import { revalidatePath, revalidateTag } from 'next/cache';
    import { NextRequest, NextResponse } from 'next/server';
    
    export async function POST(request: NextRequest) {
      const { secret, path, tag } = await request.json();
    
      if (secret !== process.env.REVALIDATION_SECRET) {
        return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
      }
    
      if (path) {
        revalidatePath(path);
      }
    
      if (tag) {
        revalidateTag(tag);
      }
    
      return NextResponse.json({ revalidated: true });
    }
    

    Database Connections

    Connection Pooling with Prisma

    // lib/db.ts
    import { PrismaClient } from '@prisma/client';
    
    const globalForPrisma = globalThis as unknown as {
      prisma: PrismaClient | undefined;
    };
    
    export const db = globalForPrisma.prisma ?? new PrismaClient({
      log: process.env.NODE_ENV === 'development' ? ['query'] : [],
    });
    
    if (process.env.NODE_ENV !== 'production') {
      globalForPrisma.prisma = db;
    }
    

    Vercel Postgres

    // lib/db.ts
    import { sql } from '@vercel/postgres';
    
    export async function getUsers() {
      const { rows } = await sql`SELECT * FROM users`;
      return rows;
    }
    
    export async function createUser(email: string, name: string) {
      const { rows } = await sql`
        INSERT INTO users (email, name)
        VALUES (${email}, ${name})
        RETURNING *
      `;
      return rows[0];
    }
    

    Vercel KV (Redis)

    // lib/cache.ts
    import { kv } from '@vercel/kv';
    
    export async function cacheGet<T>(key: string): Promise<T | null> {
      return kv.get(key);
    }
    
    export async function cacheSet<T>(key: string, value: T, ttl?: number): Promise<void> {
      if (ttl) {
        await kv.set(key, value, { ex: ttl });
      } else {
        await kv.set(key, value);
      }
    }
    
    // Rate limiting example
    export async function rateLimit(ip: string, limit: number, window: number): Promise<boolean> {
      const key = `rate-limit:${ip}`;
      const current = await kv.incr(key);
    
      if (current === 1) {
        await kv.expire(key, window);
      }
    
      return current <= limit;
    }
    

    CLI Commands

    # Install Vercel CLI
    npm i -g vercel
    
    # Login
    vercel login
    
    # Link project
    vercel link
    
    # Deploy
    vercel                    # Preview deployment
    vercel --prod             # Production deployment
    
    # Environment variables
    vercel env ls
    vercel env add DATABASE_URL production
    vercel env pull .env.local
    
    # Domains
    vercel domains ls
    vercel domains add example.com
    vercel domains verify example.com
    
    # Logs
    vercel logs
    vercel logs --follow
    
    # Secrets (deprecated, use env)
    vercel secrets ls
    
    # Project settings
    vercel project ls
    vercel inspect [deployment-url]
    
    # Rollback
    vercel rollback [deployment-url]
    

    Performance Checklist

    • Use Edge Functions for auth/redirects
    • Enable ISR for dynamic content
    • Configure proper cache headers
    • Use next/image for images
    • Minimize client-side JavaScript
    • Use streaming where applicable
    • Configure proper regions
    • Set up monitoring (Vercel Analytics)

    Security Checklist

    • Environment variables for secrets
    • CORS headers configured
    • Rate limiting on APIs
    • Input validation
    • CSP headers set
    • No secrets in client code

    Integration

    Works with:

    • /react - Next.js development
    • /devops - CI/CD pipelines
    • /security - Security headers
    • /benchmark - Performance testing
    Recommended Servers
    Vercel
    Vercel
    Repository
    liauw-media/codeassist
    Files