Vercel edge network and functions

Vercel’s compute story has three layers stacked at progressively-deeper distance from the user: the Edge Network (126+ POPs, runs only routing + middleware + edge functions on V8 isolates), Vercel Functions (regional Node.js / Python — full-fat runtime, now defaulting to the Fluid Compute concurrency model), and Incremental Static Regeneration (cached HTML between them). The big 2024-2025 shift was Fluid Compute — Functions instances are now reused across concurrent requests, eliminating the strict one-instance-per-request model that defined AWS Lambda since 2014. For AI / I/O-bound workloads, Fluid often cuts costs 40-70% vs the legacy per-invocation pricing.

See also

1. The three runtime tiers

Per vercel.com/docs/functions/runtimes. Vercel exposes three primary runtimes:

RuntimeBacked byCold startMemoryMax durationUse for
EdgeV8 isolates (on Cloudflare-compatible runtime)~5-50ms128 MB25s (streaming) / 30sMiddleware, low-latency redirects, lightweight APIs, geographic routing
Node.js (Fluid)Node 22 in firecracker microVM with concurrent request handling~50-300ms first; ~0ms reusedUp to 4 GB60s (Hobby) / 800s (Pro) / 15min (Enterprise)AI APIs, database access, business logic
PythonPython 3.12 in microVM~200-500msUp to 4 GBSame as NodePython-specific libs (numpy, pandas, ML libs)

The retired-but-still-callable Serverless (non-Fluid) runtime is the legacy one-instance-per-request model. New projects default to Fluid. Existing projects can opt in via Project Settings → Functions → Fluid Compute.

2. Edge Network — the CDN layer

Per vercel.com/docs/cdn. The Vercel Delivery Network is a globally distributed CDN with:

  • 126+ POPs across 51 countries (per vercel.com/docs/regions).
  • 20+ regional compute regions where Functions actually run (e.g. iad1 = us-east-1 region).
  • Framework-aware caching — for supported frameworks (Next.js, SvelteKit, Nuxt, Astro), cache rules are derived from your routing config at build time, not hand-written.
  • Always-on DDoS mitigation + WAF included on every deployment.

Request flow:

User → POP (closest of 126) → CDN cache check
                              ↓ miss
                            → Edge runtime (middleware + edge functions)
                              ↓ if needs origin compute
                            → Function region (regional)
                              ↓ if needs upstream
                            → Origin (your database / external API)

3. Routing Middleware — code at the edge

Per vercel.com/docs/routing-middleware. Middleware runs before the CDN cache check, at every POP. Use for:

  • Auth (verify JWT, redirect to login).
  • Geographic routing (different content per country).
  • A/B testing (rewrite to a variant).
  • Bot detection / rate limiting.
  • Custom headers.
// middleware.ts (Next.js)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
 
export function middleware(request: NextRequest) {
  // Geo-block
  const country = request.geo?.country ?? "US";
  if (["CN", "RU"].includes(country)) {
    return new NextResponse("Not available in your region", { status: 451 });
  }
  
  // Auth check
  const token = request.cookies.get("auth-token");
  if (!token && request.nextUrl.pathname.startsWith("/dashboard")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
  
  // Pass through
  return NextResponse.next();
}
 
export const config = {
  // matcher restricts which paths invoke middleware
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};

Important: middleware runs on every request that matches, including cached responses. A poorly-scoped matcher means middleware runs on every static asset request — that’s expensive at the Edge Request tier. Always use a tight matcher.

Middleware runs in the Edge runtime — V8 isolate, no Node.js APIs (no fs, no native modules). Use fetch for any I/O.

4. Vercel Functions — request handlers

Per vercel.com/docs/functions. A function is a file that exports a request handler. The recommended shape (modern Vercel):

// api/hello.ts
export default {
  async fetch(request: Request): Promise<Response> {
    return new Response("Hello from Vercel!");
  },
};

Or framework-specific (Next.js App Router):

// app/api/hello/route.ts
export async function GET(request: Request) {
  return new Response("Hello from Vercel!");
}
 
export async function POST(request: Request) {
  const data = await request.json();
  return Response.json({ received: data });
}

Choosing the runtime per-function (Next.js App Router):

// app/api/chat/route.ts
export const runtime = "edge";       // V8 isolates — for streaming AI
// or
export const runtime = "nodejs";     // Node.js — default

vercel.json config per-route:

{
  "functions": {
    "api/heavy.ts": {
      "runtime": "nodejs22.x",
      "memory": 3008,
      "maxDuration": 300
    },
    "api/edge.ts": {
      "runtime": "edge"
    }
  }
}

5. Fluid Compute — the concurrency model

Per vercel.com/docs/fluid-compute. The headline change: a single function instance can handle multiple concurrent requests instead of one-per-instance (Lambda style). For I/O-bound work (AI inference, database queries), most of the request lifecycle is waiting — Fluid uses that idle time to process other requests on the same instance.

How it works:

  • Each instance has configurable max concurrency (Vercel auto-tunes, typically 100-1000).
  • When a request comes in, the router prefers an existing warm instance with capacity. Only spawns a new instance when all warm instances are at capacity.
  • Idle instances are kept warm for ~5 minutes (drastically reducing cold starts).
  • Billing is active CPU time + provisioned memory time — you pay for what you actually use, not request count × full max-duration.
// Fluid Compute uses standard async patterns — no special API
export async function POST(request) {
  // While this awaits the OpenAI response, the instance can handle other requests
  const result = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: { "Authorization": `Bearer ${process.env.OPENAI_API_KEY}` },
    body: JSON.stringify({ ... }),
  });
  return result;
}

Concurrency tuning: Vercel handles this automatically, but for CPU-bound work you can override:

{
  "functions": {
    "api/cpu-heavy.ts": {
      "concurrency": 1   // disable concurrency for CPU-bound work
    }
  }
}

6. Streaming responses

Per vercel.com/docs/functions/streaming-functions. Critical for AI / LLM use cases — let the model stream tokens as they’re generated rather than waiting for the full response.

// app/api/chat/route.ts
import { streamText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
 
export async function POST(request: Request) {
  const { messages } = await request.json();
  
  const result = streamText({
    model: anthropic("claude-sonnet-4-6"),
    messages,
  });
  
  return result.toDataStreamResponse();
}
 
export const runtime = "edge";       // Edge is best for streaming — lowest overhead
export const maxDuration = 25;       // Edge max duration for streaming

Streaming + Edge runtime is the canonical AI API shape on Vercel — minimum cold start, geographic distribution, no Lambda-style timeout issues for long streams.

7. Regions

Per vercel.com/docs/regions. Functions run in one specific region per project unless overridden. Default: iad1 (Washington, D.C., USA).

Region list (partial):

  • iad1 — Washington, D.C., USA
  • pdx1 — Portland, OR, USA
  • sfo1 — San Francisco, USA
  • cdg1 — Paris, France
  • fra1 — Frankfurt, Germany
  • lhr1 — London, UK
  • dub1 — Dublin, Ireland
  • bom1 — Mumbai, India
  • sin1 — Singapore
  • syd1 — Sydney, Australia
  • gru1 — São Paulo, Brazil
  • hnd1 — Tokyo, Japan
  • sjc1 — San Jose, USA
  • arn1 — Stockholm, Sweden
  • icn1 — Seoul, South Korea

Pick a region close to your data source — for a function that queries a Postgres in AWS us-east-1, pick iad1 (same region). The 80ms latency of cross-region DB queries dominates everything else.

Multi-region functions (Enterprise) — same code runs in multiple regions; Vercel routes to the nearest. Worth it only if your data is also multi-region replicated.

8. Pricing — Fluid Compute

Per vercel.com/docs/functions/usage-and-pricing. Fluid Compute has three metering dimensions:

DimensionWhat it measuresHobby (free)Pro includedOverage
Active CPU timeFunction actively executing JS / Python (not waiting on I/O)Limited4 vCPU-hours$0.128 / vCPU-hour
Provisioned memory timeMemory × wall-clock time the instance was alive100 GB-Hours360 GB-Hours$0.0094 / GB-hour
InvocationsFunction entry counts (not requests — invocations)100k1M$0.6 / million

Compared to legacy serverless (which billed per-invocation × max-duration), Fluid is dramatically cheaper for I/O-bound work. A function waiting 5s on an LLM and using minimal CPU costs ~10% of what it would have under legacy billing.

9. Limits

Per vercel.com/docs/functions/limitations:

LimitEdgeNode.js (Fluid)
Max bundle size (compressed)1 MB (Free), 4 MB (Pro)50 MB
Max bundle size (uncompressed)4 MB (Free), 8 MB (Pro)250 MB
Memory128 MB128 MB - 4 GB
CPU time per request50msunbounded within max duration
Max duration25s (streaming) / 30s60s (Hobby) / 800s (Pro) / 900s (Enterprise)
Concurrent connections to same functionAutoAuto
Body size limit4.5 MB4.5 MB
Response size limit4.5 MB sync, unlimited streaming4.5 MB sync, unlimited streaming

Edge’s 1MB code limit is a real constraint for AI apps. Many AI SDKs (LangChain) bundle to > 1MB on Edge. Workaround: use a smaller AI library (Vercel AI SDK is < 50KB), or move to Node.js runtime.

10. Incremental Static Regeneration (ISR)

Per vercel.com/docs/incremental-static-regeneration. ISR serves cached static HTML, regenerating in the background on a schedule or trigger.

Two regeneration modes:

10.1 Time-based revalidation

// Next.js App Router
export const revalidate = 60;   // re-generate at most once every 60 seconds
 
export default async function Page() {
  const data = await fetch("https://api.example.com/data").then(r => r.json());
  return <div>{data.headline}</div>;
}

10.2 On-demand revalidation

Trigger a revalidation from any Function (e.g. webhook from CMS):

import { revalidatePath, revalidateTag } from "next/cache";
 
export async function POST(request: Request) {
  await verifyWebhookSignature(request);
  
  revalidatePath("/products");                 // revalidate one path
  revalidateTag("products");                   // revalidate everything tagged "products"
  
  return Response.json({ revalidated: true });
}

ISR is request-collapsing — if 1000 users hit /products at the same moment after the cache expires, only one regeneration runs and all 1000 get the result. No thundering herd.

11. Image Optimization

Per vercel.com/docs/image-optimization. Vercel’s image pipeline:

  • Resize / crop / convert (WebP / AVIF) on the fly.
  • Cache transformed images on the CDN.
  • Use <Image> component (Next.js) or _next/image URLs directly.

Defaults: 90% quality, WebP. Set quality={...} for less compression. Image URLs include a hash so cache busts on source change.

Pricing: $5 / 1k images optimized (overage). Hobby includes 1000 source images / month.

Image optimization at the edge (re:Invent / 2024) — most transforms happen at the POP, not the origin region. Latency on uncached images is ~100-300ms; cached images serve in < 50ms.

12. Caching tiers

Per vercel.com/docs/caching. Three layers:

LayerWhereTTLGranularity
CDN cacheAt POPs globallySet by Cache-Control headers or framework rulesPer URL
Runtime cacheInside the Function instanceSet explicitlyPer fetch / per query
ISR cacheAt POPs + originSet by revalidatePer page

The runtime cache (re:Invent 2024) is a new layer — it caches fetch() results, DB query results, and any function inside the warm function instance:

import { unstable_cache } from "next/cache";
 
const getUser = unstable_cache(
  async (id) => db.users.findUnique({ where: { id } }),
  ["user"],
  { revalidate: 60, tags: ["users"] }
);

When the same function instance handles multiple requests (Fluid Compute), the cache shortens calls dramatically.

13. Edge Config — for ultra-low-latency reads

Per vercel.com/docs/edge-config. A globally-replicated read-only-ish data store accessible from Middleware and Functions. Reads return in < 1ms at the median (cache-local in the POP). Writes propagate in a few seconds.

import { get } from "@vercel/edge-config";
 
// In middleware or edge function
const featureFlag = await get("new-checkout-enabled");

Use for: feature flags, A/B test config, redirects, blocklists. Don’t use for: anything that changes often, anything per-user, anything > 512 KB.

See vercel-storage-and-data for details.

14. WebSockets — coming soon

As of 2026-05-25, Vercel Functions don’t natively support WebSocket connections (Edge or Node.js). The workaround is to use a third-party WebSocket provider (Pusher, Ably, Liveblocks, Soketi) called from your Functions.

SSE (Server-Sent Events) works — that’s what streamText uses for AI streaming. SSE is one-way (server → client) which covers most streaming use cases. For bidirectional, use a hosted service.

Further reading