vercel-deployment

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

16 stars

Best use case

vercel-deployment is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

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

Teams using vercel-deployment should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/vercel-deployment/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/development/vercel-deployment/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/vercel-deployment/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How vercel-deployment Compares

Feature / Agentvercel-deploymentStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

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

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# 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

```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)

```javascript
/** @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

```typescript
// 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

```typescript
// 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)

```typescript
// 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

```typescript
// 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

```bash
# .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

```javascript
// 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

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

### Preview Environment Variables

```bash
# 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

```yaml
# .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

```typescript
// 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)

```typescript
// 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

```typescript
// 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

```typescript
// 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

```typescript
// 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)

```typescript
// 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

```bash
# 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

Related Skills

vercel

16
from diegosouzapw/awesome-omni-skill

Deploys applications to Vercel including serverless functions, edge functions, environment variables, and CI/CD. Use when deploying Next.js applications, frontend projects, or serverless APIs.

vercel-workflow-sdk

16
from diegosouzapw/awesome-omni-skill

write code that uses https://useworkflow.dev/ on Vercel

vercel-web-design-guidelines

16
from diegosouzapw/awesome-omni-skill

Reviews UI code for compliance with web interface best practices. Use when auditing accessibility, reviewing UI/UX patterns, checking performance, or improving web design quality. Triggers on "check my site", "audit design", "accessibility review", "UX best practices", or UI code review tasks. Covers 100+ rules for accessibility, performance, and user experience.

vercel-react-best-practices

16
from diegosouzapw/awesome-omni-skill

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

vercel-deploy

16
from diegosouzapw/awesome-omni-skill

Deploy applications and websites to Vercel. Use this skill when the user requests deployment actions such as "Deploy my app", "Deploy this to production", "Create a preview deployment", "Deploy and give me the link", or "Push this live". No authentication required - returns preview URL and claimable deployment link.

vercel-deploy-claimable

16
from diegosouzapw/awesome-omni-skill

Deploy applications and websites to Vercel. Use this skill when the user requests deployment actions such as 'Deploy my app', 'Deploy this to production', 'Create a preview deployment', 'Deploy and...

vercel-composition-patterns

16
from diegosouzapw/awesome-omni-skill

React composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.

vercel-ai-sdk-development

16
from diegosouzapw/awesome-omni-skill

Use when building AI-powered applications with the Vercel AI SDK (V6+). Covers agents (ToolLoopAgent), tool design with execution approval and strict mode, MCP client integration, structured output with tool calling, streaming patterns, DevTools debugging, reranking, provider-specific tools, and UI integration with React/Next.js.

vercel-ai-sdk-best-practices

16
from diegosouzapw/awesome-omni-skill

Best practices for using the Vercel AI SDK in Next.js 15 applications with React Server Components and streaming capabilities.

managing-vercel

16
from diegosouzapw/awesome-omni-skill

Vercel platform CLI for frontend deployments, serverless functions, and edge network management. Use for deploying applications, managing domains, environment variables, and debugging deployments.

vercel-automation

16
from diegosouzapw/awesome-omni-skill

Automate Vercel tasks via Rube MCP (Composio): manage deployments, domains, DNS, env vars, projects, and teams. Always search tools first for current schemas.

vercel-secure-deploy

16
from diegosouzapw/awesome-omni-skill

将 Google AI Studio 项目部署到 Vercel。当用户提到"部署"、"上线"、"发布网站"、"Vercel"、"保护 API 密钥"时触发。