Vercel's free tier is generous enough that most developers never think about billing — until they do. Then they get a bill for hundreds of dollars on a project they thought was essentially free, and they don't understand why.

This guide breaks down exactly how Vercel function pricing works, what triggers cost spikes, and the practical changes that bring bills back under control without migrating away from Vercel.

How Vercel Actually Charges for Functions

With Fluid compute - now the default on Hobby, Pro, and new Enterprise teams - Vercel charges for functions on three dimensions: Active CPU time (billed only while your code is actually running), Provisioned Memory (billed for the memory an instance holds the whole time it is alive, including time spent waiting on I/O), and the number of invocations. For AI workloads, which spend most of their time waiting on model APIs, the Active CPU model is what matters most.

Metric What It Measures Pro Plan Included Overage Rate
Function Invocations Each time a function is called Billed on-demand (Pro) $0.60 per 1M
Active CPU time CPU time your code actively runs (I/O wait excluded) Billed on-demand (Pro) ~$0.128 per CPU-hour (US regions; varies)
Provisioned Memory Memory allocated × instance uptime Billed on-demand (Pro) ~$0.0106 per GB-hour (US regions; varies)
Fast Data Transfer Data transferred out 1 TB / month $0.15 per additional GB

Provisioned Memory is the dimension that surprises people. An instance is billed for its allocated memory the entire time it stays alive - including the seconds it spends waiting on an LLM response - while Active CPU is billed only for the milliseconds your code actually runs. A route that allocates 2 GB and stays alive for 10 seconds waiting on a model API pays for about 2 GB x 10s of provisioned memory (a fraction of a cent) plus the small slice of Active CPU it actually used. Because you no longer pay CPU rates for idle wait time, idle-heavy AI routes are dramatically cheaper under Active CPU pricing than under the old GB-seconds model.

The Five Patterns That Cause Unexpected Bills

1. AI API Calls Inside Functions

Calling OpenAI or Anthropic inside a serverless function keeps an instance alive for the whole call - often 2 to 30 seconds. Under Active CPU pricing that idle wait is billed at the low provisioned-memory rate rather than the CPU rate, which softens the old GB-seconds blow, but long, memory-heavy, high-volume AI routes still add up across provisioned memory and invocations.

// This pattern is expensive at scale
export async function POST(req: Request) {
  const response = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [...],
    max_tokens: 4096,
  });
  // Function stays alive 8-15 seconds, billing memory for the wait
  return Response.json(response);
}
Each long LLM call keeps a function instance alive, billing provisioned memory for the full wait plus the invocation. At scale, this can still be cheaper to offload to a background job service (Trigger.dev, Inngest) or a dedicated compute provider (Railway, Modal).

2. Missing Response Caching

Every request that reaches a function is a billable invocation. Static or semi-static content that regenerates on every request wastes both invocations and compute time.

// Without caching: every request hits the function
export async function GET() {
  const data = await fetchFromDatabase();
  return Response.json(data);
}
 
// With caching: CDN serves most requests; function only runs on cache miss
export async function GET() {
  const data = await fetchFromDatabase();
  return Response.json(data, {
    headers: {
      'Cache-Control': 's-maxage=60, stale-while-revalidate=300',
    },
  });
}

3. Middleware Running on Every Request

Vercel Middleware runs on the Edge — which is fast and cheap per invocation, but it runs on every single request including static assets, images, and CSS files. If you're doing database lookups in middleware, you're paying for a database round-trip on every page load.

// Bad: middleware with DB lookup runs on EVERY request
export function middleware(request: NextRequest) {
  const session = await db.getSession(request.cookies.get('session'));
  // This DB call runs for .css, .js, .png requests too
}
 
// Good: only run expensive logic on API routes and pages
export const config = {
  matcher: ['/api/:path*', '/dashboard/:path*'],
};

4. Waterfall Database Queries

Functions that make multiple sequential database calls multiply both duration and memory usage. A function making 5 sequential Postgres queries might run for 800ms instead of 150ms.

// Sequential queries: ~800ms total
const user = await db.getUser(userId);
const org = await db.getOrg(user.orgId);
const docs = await db.getDocs(org.id);
const perms = await db.getPermissions(user.id);
 
// Parallel queries: ~200ms total
const [user, perms] = await Promise.all([
  db.getUser(userId),
  db.getPermissions(userId),
]);
const [org, docs] = await Promise.all([
  db.getOrg(user.orgId),
  db.getDocs(user.orgId),
]);

5. Oversized Function Bundles

Cold starts become more expensive when your function bundle is large. A function that imports an entire ML library or PDF processing package on every cold start adds 2-5 seconds of initialisation time - all billed as Active CPU and provisioned memory.

// Avoid: importing heavy libraries at module level
import { PDFDocument } from 'pdf-lib'; // loaded on every cold start
 
// Better: dynamic import only when needed
export async function POST(req: Request) {
  if (req.headers.get('content-type')?.includes('pdf')) {
    const { PDFDocument } = await import('pdf-lib');
    // ...
  }
}

Serverless Functions vs Edge Functions: When to Use Each

Serverless Functions Edge Functions / Middleware
Runtime Node.js (full) V8 isolates (limited APIs)
Max Duration 300s default, up to 800s (Pro/Ent) 25s to first byte; up to 300s streaming
Memory Up to 4 GB 128 MB
Cold Start 100–500ms 0–5ms (no cold start)
Cost Model Active CPU + provisioned memory + invocations Same Fluid compute model
Best For DB queries, AI calls, heavy processing Auth checks, redirects, geolocation, A/B tests
Move auth checks, redirects, and simple header manipulation to Edge Middleware. Reserve serverless functions for work that requires Node.js APIs or significant memory. This reduces both cold start impact and compute cost.

Practical Cost Reduction Strategies

Set Function Memory and Duration Limits

Vercel functions default to 2 GB memory (1 vCPU). Most API routes need far less, and on Pro/Enterprise you can lower the default. Reducing provisioned memory both cuts cost and surfaces memory-pressure bugs early.

// vercel.json — configure per-route function settings
{
  "functions": {
    "app/api/chat/route.ts": {
      "memory": 512,
      "maxDuration": 30
    },
    "app/api/data/route.ts": {
      "memory": 256,
      "maxDuration": 10
    }
  }
}

Use Spend Limits (Vercel Pro)

Vercel Pro allows you to set a monthly spend cap that pauses function execution when reached rather than running up an unlimited bill. This is not enabled by default — you must set it explicitly.

Go to: Vercel Dashboard > Settings > Billing > Spend Management. Set a limit below your comfort threshold. Your site continues serving cached static content even when the cap is hit; only dynamic function execution pauses.

The spend cap only applies to overages above the plan's included usage. It does not prevent you from being charged for your base plan.

Move Long-Running Work Off Vercel Functions

If you're running LLM chains, document processing, or any work that regularly takes more than 5 seconds, Vercel functions are the wrong tool. Options:

  • Trigger.dev or Inngest: offload to a background job, return a job ID immediately, poll for completion
  • Railway or Render: run a dedicated Node.js server for long-running endpoints — flat monthly rate, no per-second billing
  • Modal: for GPU-accelerated AI inference — pay per compute, not per wall-clock second of a waiting function
// Pattern: offload to Trigger.dev, return job ID immediately
import { tasks } from '@trigger.dev/sdk/v3';
 
export async function POST(req: Request) {
  const { documentId } = await req.json();
 
  // Enqueue the job — returns immediately (< 100ms)
  const handle = await tasks.trigger('process-document', { documentId });
 
  // Return job ID; client polls /api/jobs/[id] for status
  return Response.json({ jobId: handle.id });
  // Vercel function ran for ~100ms instead of 30 seconds
}

Reading Your Vercel Bill

Vercel's usage dashboard (Settings > Billing > Usage) breaks down consumption by function path. Sort by Active CPU (or Provisioned Memory) descending - the top 3 functions almost always account for 80%+ of your bill. Fix those first.

The Functions tab in Vercel Analytics shows p50, p95, and p99 duration for each route. If your p95 duration is above 5 seconds for any route, that route is the target for optimisation.

Enable Vercel's spending notifications under Settings > Billing > Notifications. Set alerts at 50% and 80% of your expected monthly spend. You want to know before the bill arrives, not after.

When to Leave Vercel

Vercel is the right choice when: you're building a Next.js application, your functions are short-lived (< 5 seconds), and the developer experience value outweighs the per-invocation cost.

Consider alternatives when: your functions regularly run for 10+ seconds, you're running AI workloads that need GPU access, or you want predictable flat-rate hosting costs. Railway and Render offer flat monthly pricing; Modal offers pay-per-compute for AI workloads.

The hybrid approach works well in practice: Vercel for the frontend and short API routes, Railway or Render for long-running backend services, and Modal for GPU inference — all behind a single domain using Vercel Rewrites to proxy to the backend.

Metadata Value
Title The True Cost of Vercel Functions at Scale: What the Pricing Page Doesn't Tell You
Tool Vercel
Primary SEO keyword vercel function cost
Secondary keywords vercel pricing serverless, vercel functions expensive, vercel GB-seconds, vercel spend limit
Estimated read time 10 minutes
Research date 2026-04-14