Classic serverless has a hidden cost. Each request gets its own function instance, and you pay for the whole time it runs, including the seconds it spends waiting for a database or an AI model to answer. For modern apps that call slow APIs, most of that time is idle.

Vercel's answer is Fluid compute, the default for new projects since April 2025, together with Active CPU pricing. This guide explains what changed, what it means for your code, and how to keep bills predictable.

What Fluid compute changes

In the traditional model, one instance handles one request at a time. Fluid compute lets a single instance handle multiple invocations concurrently. While one request is waiting on a network call, the same instance can start working on another.

Vercel's docs list the main effects:

  • Fewer cold starts, because warm instances are reused more often.
  • Better efficiency for I/O-heavy work such as calling LLM APIs, databases and third-party services.
  • Background work after the response with waitUntil.

Optimised concurrency is available for the Node.js and Python runtimes.

How Active CPU pricing works

Active CPU pricing splits the bill into three parts, according to Vercel's announcement:

  • Active CPU time: charged only while your code is actually using the CPU, starting at $0.128 per hour on Vercel's pricing page.
  • Provisioned memory: charged per GB-hour for as long as the instance is alive, at $0.0106 per GB-hour.
  • Invocations: a charge per function call.

The important change is the first line. Time spent awaiting a fetch to an AI provider is no longer billed at the CPU rate. For a function that spends most of its life waiting, this can cut costs significantly. Rates can change and may vary by region, so check the Vercel pricing page for current numbers.

Is Fluid compute on for your project?

New projects have it on by default. Older projects, or projects created from templates that pinned the previous settings, may not. Check Project Settings → Functions in the dashboard, or set it explicitly in vercel.json:

json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "fluid": true
}

Redeploy after changing it; the setting applies to new deployments.

Code that is safe under concurrency

Concurrency inside one instance means module-level state is shared between requests. Code that was accidentally safe in one-request-per-instance serverless may now leak data between users.

Unsafe:

typescript
// Shared by every request handled by this instance
let currentUser: string | null = null

export async function GET(request: Request) {
  currentUser = request.headers.get('x-user-id')
  await slowLookup()            // another request can overwrite currentUser here
  return Response.json({ user: currentUser })
}

Safe: keep request data in local variables, and only share things that are meant to be shared, such as a database client or a cache of public data.

typescript
import { db } from '@/lib/db' // one client per instance is fine

export async function GET(request: Request) {
  const userId = request.headers.get('x-user-id')
  const profile = await db.profile.findUnique({ where: { userId } })
  return Response.json(profile)
}

Reusing a database client per instance is actually better under Fluid compute, because more requests share each connection pool. Make sure the pool size suits the number of concurrent requests.

Do work after responding with waitUntil

Logging, analytics and cache warming should not make the user wait. waitUntil from @vercel/functions keeps the function alive until a promise settles, after the response has been sent:

typescript
import { waitUntil } from '@vercel/functions'

export async function POST(request: Request) {
  const order = await request.json()
  const saved = await saveOrder(order)

  waitUntil(sendAnalyticsEvent('order_created', { id: saved.id }))

  return Response.json(saved, { status: 201 })
}

Background work still counts toward the function's duration, and should be short. Use a proper queue for anything that must be retried or takes minutes.

Duration limits

Fluid compute raised function duration limits. Vercel's docs list a default of 300 seconds on all plans, with up to 800 seconds on Pro and Enterprise. Long durations are useful for streaming AI responses, but set maxDuration explicitly for each route so a stuck request cannot run, and bill, for the maximum.

Practical ways to lower your bill

  • Stream long AI responses instead of buffering them; the user sees output sooner and the function does no extra CPU work.
  • Cache aggressively with ISR or CDN headers so most requests never reach a function.
  • Reduce memory size if your functions do not need it, since provisioned memory is billed for the whole instance lifetime.
  • Move heavy CPU work (image processing, large JSON transforms) out of the request path or into a dedicated service.
  • Watch the usage dashboard after enabling Fluid compute, and compare Active CPU with memory hours.

Key takeaways

  • Fluid compute lets one function instance serve many requests at once and is the default for new Vercel projects.
  • Active CPU pricing bills CPU only while code runs, plus memory and invocations, which favours I/O-heavy apps.
  • Never keep per-request data in module-level variables.
  • Use waitUntil for short background work after responding.
  • Set maxDuration per route and cache wherever you can.

Sources: Vercel Fluid compute docs, Introducing Active CPU pricing, Fluid compute default changelog, Vercel pricing.