Skip to content
Back to skills

Vercel Optimize

ASecurity

Optimizes Vercel-deployed applications for cost, performance, and reliability through cold start mitigation, caching strategy, edge function optimization, bundle auditing, and monitoring.

  • 4 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added June 12, 2026
developmentjavascripttypescriptgojavareactnextjsnodenodejsgitapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned June 12, 2026

npx -y skills add paulpas/agent-skill-router --skill vercel-optimize --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Vercel Optimize?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Vercel Optimize
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/paulpas-vercel-optimize/badge)](https://www.skillsdirectory.com/skills/paulpas-vercel-optimize)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: vercel-optimize
description: Optimizes Vercel-deployed applications for cost, performance, and reliability through cold start mitigation, caching strategy, edge function optimization, bundle auditing, and monitoring.
license: MIT
compatibility: opencode
archetypes:
  - tactical
  - diagnostic
  - strategic
anti_triggers:
  - brainstorming
  - vague ideation
response_profile:
  verbosity: medium
  directive_strength: high
  abstraction_level: operational
metadata:
  version: "1.0.0"
  domain: coding
  triggers: vercel optimize, vercel performance, cold start, vercel caching, vercel analytics, edge functions, vercel cost
  role: implementation
  scope: implementation
  output-format: code
  content-types: [code, guidance, do-dont, examples, config]
  related-skills: react-native-rendering
  author: https://github.com/vercel-labs
  source: https://github.com/vercel-labs/agent-skills
---

# Vercel Application Optimization

A senior Vercel platform engineer who optimizes deployed applications for cost, performance, and reliability — mitigating cold starts, tuning CDN caching, optimizing Edge Functions, reducing bundle size, and setting up monitoring dashboards.

## TL;DR Checklist

- [ ] Audit performance baseline with Vercel Analytics or Lighthouse CI before optimizing
- [ ] Mitigate cold starts by migrating latency-sensitive endpoints to Edge Functions
- [ ] Configure CDN caching with `stale-while-revalidate` for dynamic content and `immutable` for static assets
- [ ] Split bundles at route level with `next/dynamic` and lazy-load heavy dependencies
- [ ] Optimize images with next/image configuration (formats, sizes, remotePatterns, loader)
- [ ] Use Next.js Script component with appropriate strategy for third-party scripts
- [ ] Set up Vercel Analytics, Speed Insights, and Logs for ongoing monitoring
- [ ] Track per-function execution cost to identify expensive operations

---

## When to Use

Use this skill when:

- A Next.js app on Vercel has slow page loads or high Time-to-First-Byte (TTFB)
- Serverless function cold starts are noticeable (response times >500ms on first request)
- The monthly Vercel bill is growing faster than traffic
- Lighthouse scores are below 90 for Performance
- Images are unoptimized (large file sizes, wrong formats, missing dimensions)
- Third-party scripts block page rendering (no strategy-based loading)
- You need to implement ISR (Incremental Static Regeneration) with on-demand revalidation

---

## When NOT to Use

Avoid this skill for:

- Apps not deployed on Vercel (different platform, different optimization strategies)
- Static sites with zero server-side computation — Vercel's defaults are already optimal
- Prototyping or staging environments where optimization overhead isn't justified
- Before establishing performance baselines — always measure the problem first

---

## Core Workflow

1. **Audit Performance** — Establish baseline metrics:
   - Enable Vercel Analytics and Speed Insights in the project dashboard
   - Run Lighthouse CI on critical pages and record LCP, CLS, INP scores
   - Identify pages with high TTFB (above 500ms), large bundle sizes, or unoptimized images
   - Check Vercel Logs for function execution duration and error rates
   **Checkpoint:** Document baseline values for every metric you plan to improve. Without baselines, you cannot measure success.

2. **Address Cold Starts** — Reduce serverless function latency:
   - Migrate latency-sensitive endpoints from Serverless Functions to Edge Functions (sub-50ms start)
   - Implement lambda warmers for Serverless Functions that cannot be migrated
   - Use `keep-alive` connections to reuse database and API connections across invocations
   - Decrease function memory allocation if underutilized (cold starts scale with memory)
   **Checkpoint:** Verify that cold start latency drops below 200ms for critical paths. Retest from a fresh region.

3. **Optimize Caching Strategy** — Reduce origin requests:
   - Configure `Cache-Control` headers with `s-maxage` + `stale-while-revalidate` for dynamic pages
   - Set `immutable` with `max-age=31536000` for static assets (fonts, images, compiled CSS)
   - Implement ISR with appropriate `revalidate` intervals and on-demand revalidation webhooks
   - Use `next.config.js` `headers` for global cache policies
   **Checkpoint:** Verify cache hit rate in Vercel Analytics is above 80% for static assets and above 50% for dynamic pages.

4. **Reduce Bundle Size** — Ship less JavaScript:
   - Use `next/dynamic` with `ssr: false` for heavy client-only components (charts, maps, editors)
   - Tree-shake unused exports from large dependencies (lodash, moment, date-fns)
   - Analyze bundle with `@next/bundle-analyzer` and identify large chunks
   - Lazy-load below-the-fold components and route segments
   - Replace large dependencies with lighter alternatives
   **Checkpoint:** Run `ANALYZE=true next build` — total JS per page must be under 150KB (gzipped) for pages above the fold.

5. **Set Up Monitoring** — Ensure ongoing visibility:
   - Configure Vercel Analytics for real-user monitoring (RUM)
   - Set up Speed Insights for Core Web Vitals tracking (LCP, CLS, INP)
   - Export Vercel Logs and create custom metrics for function duration, error rate, and cache hit ratio
   - Set up budget alerts: alert when LCP exceeds 2.5s or error rate exceeds 1%
   **Checkpoint:** Verify dashboards are populated with data within 24 hours of enabling.

6. **Review Cost Metrics** — Optimize the Vercel bill:
   - Identify top-spending Serverless Functions by execution duration and invocation count
   - Migrate high-traffic Serverless Functions to Edge Functions or ISR to reduce compute cost
   - Optimize `next/image` configuration to reduce image optimization bandwidth charges
   - Review function memory allocation — over-allocated memory costs more per invocation
   **Checkpoint:** Compare current projected monthly cost vs. previous month — target 20% reduction.

---

## Implementation Patterns

### Pattern 1: Edge Function Migration (Cold Start Mitigation)

```typescript
// ❌ BAD: Serverless Function for a simple API proxy — 500ms+ cold start
// pages/api/proxy.ts (Serverless Function)
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  res.status(200).json(data);
}

// ✅ GOOD: Edge Function for the same proxy — sub-50ms cold start
// app/api/proxy/route.ts (Edge Function — works in App Router)
export const runtime = 'edge';

export async function GET(request: Request) {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return Response.json(data);
}

// ✅ GOOD: Keep-alive connection reuse for database-backed endpoints
// lib/db.ts — reuse connection across invocations
let dbClient: DatabaseClient | null = null;

export async function getDb(): Promise<DatabaseClient> {
  if (!dbClient) {
    dbClient = await createClient({
      connectionString: process.env.DATABASE_URL!,
      poolSize: 1,
      // Keep connection alive between function invocations
      idleTimeoutMillis: 60_000,
    });
  }
  return dbClient;
}

// app/api/users/route.ts — uses the cached connection
export const runtime = 'nodejs';

export async function GET() {
  const db = await getDb();  // Reuses connection on warm invocations
  const users = await db.query('SELECT * FROM users LIMIT 10');
  return Response.json(users);
}
```

### Pattern 2: Advanced Caching Strategy

```typescript
// next.config.js — global cache headers
/** @type {import('next').NextConfig} */
const nextConfig = {
  async headers() {
    return [
      {
        // Static assets: cache forever in CDN and browser
        source: '/:path*.(svg|png|jpg|jpeg|gif|webp|woff2|ttf|eot|css|js)',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, immutable',
          },
        ],
      },
      {
        // API routes: CDN cache with stale-while-revalidate
        source: '/api/:path*',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, s-maxage=60, stale-while-revalidate=600',
          },
        ],
      },
      {
        // HTML pages: short CDN cache, fallback to server
        source: '/:path((?!api|_next|static).*)',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, s-maxage=10, stale-while-revalidate=59',
          },
        ],
      },
    ];
  },
};

// ✅ GOOD: ISR with on-demand revalidation
// app/blog/[slug]/page.tsx
interface BlogPageProps {
  params: { slug: string };
}

export default async function BlogPost({ params }: BlogPageProps) {
  const post = await getPost(params.slug);
  return <article>{/* ... */}</article>;
}

// Revalidate every 60 seconds, but also trigger on-demand when content changes
export const revalidate = 60;

// app/api/revalidate/route.ts — on-demand revalidation webhook
export async function POST(request: Request) {
  const { secret, slug } = await request.json();

  // Validate secret to prevent unauthorized revalidation
  if (secret !== process.env.REVALIDATION_SECRET) {
    return Response.json({ message: 'Invalid secret' }, { status: 401 });
  }

  try {
    await revalidatePath(`/blog/${slug}`);
    return Response.json({ revalidated: true });
  } catch (err) {
    return Response.json({ message: 'Revalidation failed' }, { status: 500 });
  }
}
```

### Pattern 3: Bundle Optimization with next/dynamic

```tsx
// ❌ BAD: Heavy chart library imported eagerly — adds 120KB to the main bundle
import { LineChart } from 'recharts';

export default function Dashboard() {
  const [showChart, setShowChart] = useState(false);

  return (
    <div>
      <button onClick={() => setShowChart(true)}>Show Chart</button>
      {showChart && (
        <LineChart width={600} height={300} data={data}>
          {/* ... */}
        </LineChart>
      )}
    </div>
  );
}

// ✅ GOOD: Chart library lazy-loaded — added to a separate chunk, loaded on demand
import dynamic from 'next/dynamic';

const LazyLineChart = dynamic(
  () => import('recharts').then((mod) => mod.LineChart),
  {
    ssr: false, // Charts are client-only — no SSR needed
    loading: () => <div className="chart-skeleton h-[300px] w-[600px] bg-gray-100 animate-pulse" />,
  }
);

export default function Dashboard() {
  const [showChart, setShowChart] = useState(false);

  return (
    <div>
      <button onClick={() => setShowChart(true)}>Show Chart</button>
      {showChart && <LazyLineChart width={600} height={300} data={data} />}
    </div>
  );
}

// ✅ GOOD: Route-level code splitting with Next.js App Router
// app/dashboard/page.tsx — automatically code-split at route boundaries
export default function DashboardPage() {
  return (
    <main>
      <h1>Dashboard</h1>
      {/* Heavy components loaded per-route, not in the global layout */}
    </main>
  );
}

// app/analytics/page.tsx — separate chunk, no impact on dashboard load time
export default function AnalyticsPage() {
  return (
    <main>
      <h1>Analytics</h1>
    </main>
  );
}
```

### Pattern 4: Image Optimization with next/image

```tsx
import Image from 'next/image';

// ❌ BAD: Unoptimized image — no sizes, wrong format fallback, large dimensions
function BadHero() {
  return (
    <img
      src="/hero.png"   // Large PNG — no WebP, no AVIF
      alt="Hero"
      style={{ width: '100%', height: 'auto' }}
    />
  );
}

// ✅ GOOD: Fully optimized with next/image
function OptimizedHero() {
  return (
    <Image
      src="/hero.jpg"
      alt="Hero"
      width={1920}
      height={1080}
      sizes="(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 50vw"
      priority          // LCP element — load immediately, don't lazy-load
      quality={85}      // Balance quality vs. file size
    />
  );
}

// ✅ GOOD: next.config.js with remote image configuration
// next.config.js
const nextConfig = {
  images: {
    formats: ['image/avif', 'image/webp'],  // AVIF preferred, WebP fallback
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    minimumCacheTTL: 60 * 60 * 24 * 30,  // Cache optimized images for 30 days
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.unsplash.com',
        pathname: '/**',
      },
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
    ],
  },
};

export default nextConfig;
```

### Pattern 5: Script Loading Strategies

```tsx
// ❌ BAD: Script tag blocks rendering — no strategy, loads synchronously
export default function MarketingPage() {
  return (
    <div>
      <script src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID" />
      <script dangerouslySetInnerHTML={{
        __html: `window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);}`
      }} />
      {/* Main content — blocked until scripts load */}
    </div>
  );
}

// ✅ GOOD: Next.js Script component with appropriate strategies
import Script from 'next/script';

export default function OptimizedMarketingPage() {
  return (
    <>
      {/* Critical analytics — load before page becomes interactive, but don't block render */}
      <Script
        src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"
        strategy="afterInteractive"
      />

      {/* Chat widget — load after everything else is done */}
      <Script
        src="https://widget.intercom.io/widget/abc123"
        strategy="lazyOnload"
      />

      {/* Heatmap tool — not needed on mobile */}
      <Script
        src="https://static.hotjar.com/c/hotjar-123456.js"
        strategy="lazyOnload"
      />

      {/* Main page content renders immediately — not blocked by scripts */}
      <main>
        <h1>Welcome</h1>
        <p>This content renders before any third-party scripts load.</p>
      </main>
    </>
  );
}
```

---

## Constraints

### MUST DO
- Measure performance baselines with Vercel Analytics or Lighthouse CI before and after each optimization
- Use `stale-while-revalidate` caching for dynamic content with `s-maxage` set to acceptable freshness TTL
- Set `Cache-Control: public, max-age=31536000, immutable` for all static assets (fonts, images, compiled CSS/JS)
- Use `runtime: 'edge'` for API routes that need sub-50ms cold starts and low latency globally
- Use `next/dynamic` with `ssr: false` for heavy client-only components that are not visible above the fold
- Configure `next/image` with `formats: ['image/avif', 'image/webp']` and appropriate `remotePatterns`
- Use Next.js `<Script>` component with explicit `strategy` — never plain `<script>` tags
- Monitor Serverless Function execution durations and migrate expensive ones to Edge or ISR

### MUST NOT DO
- Use Serverless Functions for high-traffic, latency-sensitive endpoints — prefer Edge Functions or ISR
- Set `revalidate: 0` on ISR pages that don't need real-time freshness — set a reasonable TTL
- Include heavy npm packages (chart libraries, moment.js, lodash) in the main bundle — dynamic import them
- Use `<img>` tags for anything that is not a user-uploaded image with unknown dimensions
- Block page rendering with third-party scripts — always use `afterInteractive` or `lazyOnload` strategy
- Ignore Vercel Analytics data — it reveals real user performance, not just synthetic Lighthouse scores
- Optimize without cost awareness — a 10ms function improvement isn't worth 2x memory allocation

---

## Related Skills

| Skill | Purpose |
|---|---|
| `react-native-rendering` | Extends rendering optimization principles to React Native mobile apps |

---

## Live References

> Authoritative documentation links for Vercel deployment optimization.

- [Vercel Performance Guide](https://vercel.com/docs/performance) — Official performance overview
- [Vercel Edge Functions Docs](https://vercel.com/docs/functions/edge-functions) — Edge Function configuration and limits
- [Vercel Caching & CDN](https://vercel.com/docs/edge-network/caching) — CDN cache behavior and Cache-Control headers
- [Next.js Image Optimization](https://nextjs.org/docs/app/building-your-application/optimizing/images) — next/image configuration reference
- [Next.js Script Component](https://nextjs.org/docs/app/building-your-application/optimizing/scripts) — Script loading strategies
- [Vercel Analytics (RUM)](https://vercel.com/docs/analytics) — Real-user monitoring setup
- [Vercel Speed Insights](https://vercel.com/docs/speed-insights) — Core Web Vitals tracking
- [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer) — Bundle composition analysis
- [Vercel Cost Optimization](https://vercel.com/docs/accounts/plans/usage/cost-optimization) — Managing and reducing Vercel spend
- [ISR with On-Demand Revalidation](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration) — ISR revalidation patterns

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…