- name
- vercel-functions
- description
- Vercel Functions expert guidance — Node.js/Bun/Python runtimes, Fluid Compute, long-duration (30 min) functions, large functions (5 GB bundles), Docker/OCI container images, plan limits, streaming, WebSockets, and Cron Jobs. Use when configuring, debugging, or optimizing server-side code running on Vercel.
- summary
- Vercel Functions run on Fluid Compute with Node.js as the default runtime — strongly prefer it over `runtime = 'edge'` (Vercel recommends migrating off Edge, and Next.js 16.3+ no longer supports it). Duration: 300s default on every plan including Hobby, 800s max on Pro/Enterprise, 1800s (30 min) per-function in the extended beta; beyond that use Vercel Workflow. Bundles: 250 MB standard (500 MB Python), 5 GB via the large functions beta (`VERCEL_SUPPORT_LARGE_FUNCTIONS=1`). Request/response bodies cap at 4.5 MB. Memory is dashboard-only (Standard 2 GB/1 vCPU, Performance 4 GB/2 vCPU; Hobby fixed). Docker works: add `Dockerfile.vercel` to run an OCI image as an autoscaling, stateless, scale-to-zero Function.
- metadata
- {"priority":8,"docs":["https://vercel.com/docs/functions","https://vercel.com/docs/functions/runtimes","https://vercel.com/docs/functions/limitations","https://vercel.com/docs/functions/configuring-functions/duration","https://vercel.com/docs/functions/container-images","https://vercel.com/docs/fluid-compute","https://vercel.com/docs/functions/websockets"],"sitemap":"https://vercel.com/sitemap.xml","pathPatterns":["api/**/*.*","pages/api/**","src/pages/api/**","app/**/route.*","src/app/**/route.*","apps/*/api/**/*.*","apps/*/app/**/route.*","apps/*/src/app/**/route.*","apps/*/pages/api/**","vercel.json","apps/*/vercel.json","vercel.ts","apps/*/vercel.ts","Dockerfile.vercel","*/Dockerfile.vercel","Containerfile.vercel","*/Containerfile.vercel"],"bashPatterns":["\\bvercel\\s+dev\\b","\\bvercel\\s+logs\\b","\\bvercel\\s+vcr\\b"],"importPatterns":["ws","socket.io","socket.io-client"],"promptSignals":{"phrases":["websocket","websockets","web socket","socket.io","long polling","long-polling","maxduration","max duration","function timeout","function times out","long-running function","long running function","504","unzipped maximum size","250mb","250 mb","large function","bundle size limit","dockerfile","container image","container registry","runtime edge","edge runtime"],"allOf":["[Truncated]","[Truncated]"],"anyOf":["realtime","bidirectional","ws server","polling","server-sent events","fluid compute","active cpu"],"noneOf":[],"minScore":6}}
- validate
- [{"pattern":"export\\s+default\\s+function","message":"Use named exports (GET, POST, PUT, DELETE) instead of default export for route handlers","severity":"error","skipIfFileContains":"(?:^|\\n)\\s*['\"]use\\s+client['\"]|export\\s+const\\s+(?:metadata|dynamic|revalidate|fetchCache|runtime)\\b|export\\s+default\\s+(?:async\\s+)?function\\s+\\w*(?:Page|Layout|Loading|Error|NotFound|Sitemap|Template|Default|sitemap|robots|opengraph|manifest)\\b|<[A-Z][A-Za-z0-9]*|\\{\\s*children\\s*[,}:]|MetadataRoute\\.|from\\s+['\"]next/(?:font|image|link|navigation|headers|cookies)['\"]"},{"pattern":"NextApiRequest|NextApiResponse","message":"NextApiRequest/NextApiResponse are Pages Router types — use Web API Request/Response","severity":"error"},{"pattern":"runtime['\"]?\\s*[=:]\\s*['\"]edge['\"]","message":"Consider dropping `runtime = \"edge\"`. Vercel recommends migrating from Edge to Node.js, and Next.js 16.3+ no longer supports it. Node.js on Fluid Compute runs in the same regions at the same price with full Node.js APIs, longer durations, and larger bundles.","severity":"recommended"},{"pattern":"from\\s+['\"](openai|@anthropic-ai/sdk|anthropic)['\"]|new\\s+(OpenAI|Anthropic)\\(","message":"Direct AI provider SDK detected in route handler. Use the Vercel AI SDK for streaming, tools, and provider abstraction.","severity":"recommended","upgradeToSkill":"ai-sdk","upgradeWhy":"Replace vendor-locked provider SDKs with @ai-sdk/openai or @ai-sdk/anthropic for unified streaming and tool support.","skipIfFileContains":"@ai-sdk/|from\\s+['\"](ai)['\"]|import.*from\\s+['\"](ai)['\"]|streamText|generateText"},{"pattern":"setTimeout\\s*\\(|setInterval\\s*\\(|await\\s+new\\s+Promise\\s*\\([^)]*setTimeout","message":"Long-running or polling logic detected in a serverless handler. Functions have execution time limits.","severity":"recommended","upgradeToSkill":"workflow","upgradeWhy":"Move delayed/polling logic to Vercel Workflow for durable execution with pause, resume, retries, and crash safety.","skipIfFileContains":"use workflow|use step"},{"pattern":"writeFile(Sync)?\\(|createWriteStream\\(|from\\s+['\"](multer|formidable)['\"]|fs\\.writeFile","message":"Local filesystem write detected. Serverless functions have ephemeral, read-only filesystems.","severity":"error","upgradeToSkill":"vercel-storage","upgradeWhy":"Replace local filesystem writes with Vercel Blob, Neon, or Upstash for persistent, platform-native storage.","skipIfFileContains":"@vercel/blob|@upstash/|@neondatabase/"},{"pattern":"export\\s+(async\\s+)?function\\s+(GET|POST|PUT|PATCH|DELETE)\\b","message":"Route handler has no observability instrumentation. Add logging and error tracking for production debugging.","severity":"warn","skipIfFileContains":"console\\.error|logger\\.|captureException|Sentry|@vercel/otel|withTracing"},{"pattern":"from\\s+['\"\"](lru-cache|node-cache|memory-cache)['\"\"]|new\\s+(LRUCache|NodeCache|Map)\\(\\s*\\).*cache","message":"In-process memory cache detected in serverless function. Process memory is not shared across invocations.","severity":"recommended","upgradeToSkill":"runtime-cache","upgradeWhy":"Replace in-process caches with Vercel Runtime Cache (getCache from @vercel/functions) for region-aware caching that persists across invocations.","skipIfFileContains":"getCache|from\\s+['\"\"]\\@vercel/functions['\"\"]"},{"pattern":"maxRetries\\s*[=:]|retryCount\\s*[=:]|retry\\s*\\(\\s*|for\\s*\\([^)]*retry|while\\s*\\([^)]*retry","message":"Manual retry logic detected. Use Vercel Workflow SDK for automatic retries with durable execution.","severity":"recommended","upgradeToSkill":"workflow","upgradeWhy":"Replace manual retry loops with Workflow SDK steps that provide automatic retries, crash safety, and observability.","skipIfFileContains":"use workflow|use step|from\\s+['\"\"](workflow)['\"\"]"},{"pattern":"from\\s+['\"](express)['\"\"]|require\\s*\\(\\s*['\"](express)['\"\"\\)]","message":"Express.js detected in a Vercel project. Vercel Functions use the Web Request/Response API — Express middleware, req/res, and app.listen() do not work in serverless.","severity":"recommended","upgradeToSkill":"vercel-functions","upgradeWhy":"Replace Express with Next.js route handlers (export async function GET/POST) or Vercel Functions using the Web Request/Response API.","skipIfFileContains":"export\\s+(async\\s+)?function\\s+(GET|POST|PUT|PATCH|DELETE)|from\\s+['\"\"](next/server|@vercel/functions)['\"\"]"}]
- retrieval
- {"aliases":["serverless functions","api routes","edge functions","lambda","websockets","socket.io","docker","dockerfile","container images","function timeout","max duration","bundle size","hobby limits"],"intents":["create serverless function","configure function runtime","optimize cold starts","add api route","serve a websocket connection","run a function for longer than 5 minutes","deploy a dockerfile","fix a function that exceeds the bundle size limit","check plan limits for functions"],"entities":["Serverless Functions","Edge Functions","Fluid Compute","Long-duration functions","Large functions","Container Images","Vercel Container Registry","streaming","WebSockets","Cron Jobs"]}
- chainTo
- [{"pattern":"from\\s+['\\\"](openai|@anthropic-ai/sdk|anthropic)['\"]|new\\s+(OpenAI|Anthropic)\\(","targetSkill":"ai-sdk","message":"Direct AI provider SDK in route handler — loading AI SDK guidance for unified streaming and tool support."},{"pattern":"setTimeout\\s*\\(|setInterval\\s*\\(|await\\s+new\\s+Promise\\s*\\([^)]*setTimeout","targetSkill":"workflow","message":"Long-running or polling logic in serverless handler — loading Workflow SDK for durable execution."},{"pattern":"writeFile(Sync)?\\(|createWriteStream\\(|from\\s+['\\\"](multer|formidable)['\"]|fs\\.writeFile","targetSkill":"vercel-storage","message":"Local filesystem write in serverless function — loading Vercel Storage guidance for platform-native persistence."},{"pattern":"from\\s+['\"\"]@vercel/(postgres|kv)['\"\"]","targetSkill":"vercel-storage","message":"@vercel/postgres and @vercel/kv are sunset — loading Vercel Storage guidance for Neon and Upstash migration."},{"pattern":"generateObject\\s*\\(|streamObject\\s*\\(|toDataStreamResponse|maxSteps\\b|CoreMessage\\b","targetSkill":"ai-sdk","message":"Deprecated AI SDK v5 API detected — loading AI SDK guidance for migration."},{"pattern":"while\\s*\\(\\s*true\\s*\\)\\s*\\{|for\\s*\\(\\s*;\\s*;\\s*\\)\\s*\\{|setInterval\\s*\\(\\s*async","targetSkill":"workflow","message":"Polling loop in serverless function detected — loading Workflow SDK for durable, crash-safe execution with pause/resume.","skipIfFileContains":"use workflow|use step|from\\s+['\"]workflow['\"]"},{"pattern":"from\\s+['\"]express['\"]|require\\s*\\(\\s*['\"]express['\"]","targetSkill":"vercel-functions","message":"Express.js detected — loading Vercel Functions guidance for Web Request/Response API route handlers that replace Express middleware and routing.","skipIfFileContains":"export\\s+(async\\s+)?function\\s+(GET|POST|PUT|PATCH|DELETE)"},{"pattern":"from\\s+['\"\"](lru-cache|node-cache|memory-cache)['\"\"]|new\\s+(LRUCache|NodeCache|Map)\\(\\s*\\).*cache","targetSkill":"runtime-cache","message":"In-process memory cache in serverless function — loading Runtime Cache guidance for region-aware caching that persists across invocations.","skipIfFileContains":"getCache|from\\s+['\"\"]\\@vercel/functions['\"\"]"},{"pattern":"maxRetries\\s*[=:]|retryCount\\s*[=:]|retry\\s*\\(\\s*|for\\s*\\([^)]*retry|while\\s*\\([^)]*retry","targetSkill":"workflow","message":"Manual retry logic in serverless handler — loading Workflow SDK guidance for automatic retries with durable execution.","skipIfFileContains":"use workflow|use step|from\\s+['\"\"](workflow)['\"\"]"},{"pattern":"import\\s*\\{[^}]*\\bmetric\\b[^}]*\\}\\s*from\\s*['\"]@vercel/functions['\"]","targetSkill":"custom-metrics","message":"@vercel/functions metric() detected — loading Custom Metrics guidance for naming, attributes, and vc metrics queries."}]
# Vercel Functions
You are an expert in Vercel Functions — the compute layer of the Vercel platform.
## Prefer Node.js over the Edge runtime
**Strongly prefer Node.js. Don't reach for `runtime = 'edge'` in new code, and recommend migrating off it when you find it in existing code.**
This follows Vercel's own documented guidance — *"we recommend migrating from edge to Node.js for improved performance and reliability"* — and one hard constraint: as of **Next.js 16.3, `runtime = 'edge'` is no longer supported**. Routes and pages there run on Node.js regardless of what you write, so on 16.3+ this stops being a recommendation and becomes a migration you have to do.
Everywhere else it is a strong default, not a prohibition. Both runtimes run on the same Fluid Compute infrastructure, in the same regions, under the same Active CPU pricing — so in nearly every case Edge gains you nothing while costing you most of the Node.js API surface. If you have a specific, tested reason to stay on Edge, that's a legitimate call; just make it deliberately rather than by habit.
### The default to reach for
```ts
// app/api/hello/route.ts — no runtime export needed.
export async function GET() {
return Response.json({ message: 'Hello from Node.js on Fluid Compute' })
}
```
Node.js is the default. Omit `export const runtime` entirely rather than writing `export const runtime = 'nodejs'`.
### Reasons people reach for Edge — and what to do instead
| "I need Edge because…" | Reality | Do this instead |
|---|---|---|
| "…I need to stream / SSE / AI tokens" | Streaming is zero-config on Node.js. This is the single most common false belief. | Return a `ReadableStream` from a normal Node.js function |
| "…I need low latency" | Both run on Fluid Compute. Fluid pre-warms instances and caches bytecode; the difference is noise next to your DB/API round trips | Stay on Node.js; pin `regions` near your data |
| "…auth checks / redirects / A-B tests at the edge" | That's Routing Middleware's job, and **Routing Middleware supports full Node.js** — it is not edge-only | Use Routing Middleware (`routing-middleware` skill) |
| "…it's cheaper" | Identical Active CPU pricing | Stay on Node.js |
| "…it has faster cold starts" | Fluid Compute reuses warm instances across concurrent invocations and bytecode-caches Node 20+ in production | Stay on Node.js |
| "…my function must run globally" | Edge's global execution usually *hurts* — every DB query crosses an ocean | Single region (`iad1` default) next to your database |
### What Edge actually costs you
- No `fs`, no native modules, no `require()` — ESM only, and most npm packages with Node.js dependencies simply will not load
- No `eval` / `new Function` / dynamic `WebAssembly.instantiate`
- **Code size limit after gzip: 1 MB (Hobby), 2 MB (Pro), 4 MB (Enterprise)** — versus 250 MB uncompressed (up to 5 GB) on Node.js
- Must begin sending a response within **25 seconds** (it may then stream for up to 300s). The 300s/800s/1800s duration limits below apply to the Node.js, Bun, and Python runtimes — **not** to Edge
- No long-duration or large-function support of any kind
### Migrating an existing Edge function
Worth doing when you're already touching the file, and required on Next.js 16.3+. An Edge function that works today isn't an emergency.
1. Remove `export const runtime = 'edge'` (or `runtime: 'edge'` in `vercel.json` / the `config` object).
2. Replace `next/server` Edge-only imports where applicable; the Web `Request`/`Response` handler signature is unchanged, so most route handlers need no other edit.
3. If you pinned execution with the Edge-only `preferredRegion`, use `regions` in `vercel.json` instead.
4. Confirm Fluid Compute is on (default since April 23, 2025) and redeploy.
There is no rollback story to plan for: Node.js is a superset of what the function could do on Edge.
## Function Types
### Node.js (the default)
- Full Node.js runtime, all npm packages available
- Default for Next.js route handlers, Server Actions, Server Components, and any file in `/api`
- **Node.js 24 LTS is GA** for builds and functions (V8 13.6, global `URLPattern`, Undici v7, npm v11). **Node.js 20 is deprecated on October 1, 2026** — move off `nodejs20.x`
- Duration: 300s default on every plan; 800s max on Pro/Enterprise; 1800s with the extended-duration beta
### Bun
Add `"bunVersion": "1.x"` to `vercel.json` to run functions on Bun instead of Node.js. ~28% lower latency for CPU-bound workloads. Supports Next.js, Express, Hono, Nitro, and `Bun.serve` as an entrypoint. Bun supports both large functions and extended max duration.
### Python
Python 3.12 / 3.13 / 3.14 on Fluid Compute. FastAPI, Flask, and Django build into a **single** function from the resolved entrypoint — key `vercel.json` config on that entrypoint file (`app/main.py`, `myproject/wsgi.py`), not on `/api` routes. Python gets a **500 MB** standard bundle limit (vs. 250 MB) and supports large functions and extended duration.
### Rust
Rust functions run on Fluid Compute with HTTP streaming and Active CPU pricing. Official runtime (Beta) built on the `vercel_runtime` crate. Supports environment variables up to 64 KB.
### Container images (Docker)
Any OCI image via `Dockerfile.vercel`. See [Docker and Container Images](#docker-and-container-images) below.
### Edge (legacy — not recommended)
V8 isolates with a subset of Web APIs. Fine to leave in place on existing deployments, but not the runtime to pick for new work. See [Prefer Node.js over the Edge runtime](#prefer-nodejs-over-the-edge-runtime).
### Choosing a Runtime
| Need | Runtime | Why |
|------|---------|-----|
| Anything not listed below | `nodejs` | The default, and correct nearly always |
| Full Node.js APIs, npm packages | `nodejs` | Full compatibility |
| AI streaming, SSE, WebSockets | `nodejs` | Zero-config streaming, long durations |
| Lower latency, CPU-bound work | `nodejs` + Bun | ~28% latency reduction |
| Database connections, heavy deps | `nodejs` | Pin `regions` next to the database |
| Data/ML libraries, big model files | `nodejs` or `python` + large functions | Up to 5 GB bundles |
| Systems-level performance | `rust` | Native speed on Fluid Compute |
| Custom system libraries (FFmpeg, Chromium), Go/Ruby/PHP, unsupported frameworks | container image | Bring your own Dockerfile |
| Auth, redirects, A/B tests before the cache | Routing Middleware | Runs on Node.js, framework-agnostic |
| Hours-to-months of execution | Vercel Workflow | Durable steps, no duration limit |
`edge` is deliberately absent: there's no row here where it's the better answer for new code.
## Fluid Compute
Fluid Compute is the execution model for Vercel Functions — **enabled by default for new projects since April 23, 2025**, and available for the Node.js, Python, Bun, Rust, and Edge runtimes. Enable it explicitly per-deployment with `{"fluid": true}` in `vercel.json`, or project-wide in Settings → Functions.
Long-duration, large-function, and container-image support all depend on it.
Key behaviors:
- **Optimized concurrency**: multiple invocations share one instance instead of one microVM per request. Vercel prioritizes idle existing resources before allocating new ones. Available on the Node.js and Python runtimes.
- **Active CPU pricing**: you are billed for CPU time your code actually consumes, plus provisioned memory while requests are in flight, plus invocations. Waiting on I/O (AI models, DB queries) does not accrue Active CPU — which is what makes 30-minute functions affordable.
- **Automatic cold start optimization**: function pre-warming plus **bytecode caching** on Node.js 20+. Bytecode caching applies to **production only** — not dev or preview, so don't benchmark cold starts in a preview deployment.
- **Error isolation**: an uncaught exception or unhandled rejection is logged and in-flight requests are allowed to finish; one broken request will not crash its neighbors on the same instance.
- **Cross-AZ and cross-region failover**: fails over to another availability zone in-region first, then to the next closest region.
- **Graceful shutdown**: `SIGTERM` before termination (see below).
### Instance Sizes (memory / CPU)
| Type | Memory / CPU | Use |
|------|--------------|-----|
| Standard (default) | 2 GB / 1 vCPU | Predictable performance for production workloads |
| Performance | 4 GB / 2 vCPU | Latency-sensitive applications and SSR workloads |
- **With Fluid Compute enabled, memory cannot be set in `vercel.json`** — setting it there produces a build-time warning. Set it in the dashboard instead: Settings → Functions → Advanced Settings → **Function CPU**, then redeploy. (The `memory` key still exists for legacy non-Fluid deployments, which is why you will find older examples using it.)
- **Pro/Enterprise only.** Hobby always runs Standard (2 GB / 1 vCPU) and cannot configure it. The Basic instance has been removed.
- More memory also means more CPU, which can *reduce* Active CPU billing for CPU-bound work by finishing sooner — but it raises Provisioned Memory cost while requests are in flight.
- Projects created before 2019-11-08 may still sit on legacy sizes (1024 MB / 0.6 vCPU on Hobby, 3008 MB / 1.67 vCPU on Pro) until you pick a size in the dashboard.
### Settings precedence
Function code (`export const maxDuration`) → `vercel.json` → dashboard → Fluid defaults. Later entries lose.
### Background Processing with `waitUntil`
`waitUntil` takes a **Promise**, not a callback. Passing a function does nothing — a common and silent bug.
```ts
import { waitUntil } from '@vercel/functions'
export async function POST(req: Request) {
const data = await req.json()
// Correct: invoke the async work and hand over the promise.
waitUntil(processAnalytics(data))
// For several tasks, combine them:
waitUntil(Promise.all([sendNotification(data), updateCache(data)]))
return Response.json({ received: true })
}
```
### Next.js `after` (equivalent)
```ts
import { after } from 'next/server'
export async function POST(req: Request) {
const data = await req.json()
after(async () => {
await logToAnalytics(data)
})
return Response.json({ ok: true })
}
```
### Graceful shutdown and request cancellation
```ts
// Runs on scale-down. 500 ms to clean up (30 s for container images).
process.on('SIGTERM', () => {
// flush buffers, close pools
})
```
Request cancellation is **opt-in**, per path. With it enabled, a client disconnect aborts `request.signal` and terminates the function — anything not wrapped in `waitUntil`/`after` is lost, which is exactly why it is not on by default.
```json filename="vercel.json"
{
"functions": {
"api/*": { "supportsCancellation": true }
}
}
```
```ts
export async function GET(request: Request) {
// Pass the signal through so upstream work stops too.
const res = await fetch('https://upstream.example.com', { signal: request.signal })
return new Response(res.body, { status: res.status })
}
```
## Duration and Long-Duration Functions
### Duration limits
With Fluid Compute (default), per [Vercel's limits](https://vercel.com/docs/functions/limitations#max-duration):
| Plan | Default | Maximum | Extended maximum |
|------|---------|---------|------------------|
| Hobby | 300s (5 min) | 300s (5 min) | — |
| Pro | 300s (5 min) | 800s | 1800s (30 min) — Beta |
| Enterprise | 300s (5 min) | 800s | 1800s (30 min) — Beta |
The 800s maximum is **generally available** on Pro and Enterprise. The 1800s extended maximum is **in beta**. Exceeding the limit returns `504 FUNCTION_INVOCATION_TIMEOUT`.
**Hobby's default and maximum are the same 300s** — there is no headroom to raise, and no extended duration. Setting `maxDuration` above 300s on Hobby does nothing; upgrade to Pro.
### Setting `maxDuration`
```ts
// app/api/report/route.ts — Next.js App Router (and Node.js, SvelteKit, Astro,
// Nuxt, Remix via their own config). Value is in seconds.
export const maxDuration = 800
export async function POST(request: Request) {
return Response.json({ ok: true })
}
```
For other frameworks and runtimes — Next.js < 13.5, Rust, Go, Python, Ruby — use `vercel.json`:
```json
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"functions": {
"api/long-task.py": { "maxDuration": 1800 }
}
}
```
Glob order matters, and Next.js projects using `src/` must prefix paths with `src/`. For Python frameworks, key on the resolved entrypoint (`app/main.py`), not an `/api` route.
To change the project-wide default: Settings → Functions → **Function Max Duration**.
### Extended max duration (30 minutes) — Beta
Pro and Enterprise teams can run individual functions for up to **1800s**. Requirements, all of which are load-bearing:
- **Per-function configuration only.** Durations above 800s must be set in code or in `vercel.json` for that function. **Project-level defaults above 800s are not supported** during the beta — raising the dashboard default will not get you to 1800s.
- **Supported runtimes only**: `nodejs20.x`, `nodejs22.x`, `nodejs24.x`, Bun `1.x` and `1.4.x`, `python3.12`, `python3.13`, `python3.14`.
- **Fluid Compute must be enabled** (default for new projects).
- **Secure Compute and Static IPs do not support durations above 800s** during the beta. If the project uses either, you are capped at 800s.
```ts
// app/api/long-task/route.ts
export const maxDuration = 1800 // 30 minutes
export async function POST(request: Request) {
await doTheLongThing()
return Response.json({ ok: true })
}
```
### Keeping a long request alive
Over HTTP/2, Vercel sends connection-level `PING` frames while the response is idle. **HTTP/1.1 has no equivalent**, so HTTP/1.1 clients and intermediate proxies may still close an idle connection long before 30 minutes elapse. For any long-running handler, **stream progress or heartbeat data while the work runs** rather than going silent and emitting one payload at the end.
Use `getDeadline()` to find out how much time is actually left and bail out cleanly:
```ts
import { getDeadline } from '@vercel/functions'
const deadline = getDeadline() // Date | undefined (undefined outside the Vercel Functions runtime)
const msRemaining = deadline ? deadline.getTime() - Date.now() : Infinity
```
### Cost of long functions
Active CPU pricing is what makes this viable: a 25-minute function that spends 24 minutes awaiting an LLM bills almost no Active CPU, only Provisioned Memory for the instance while the request is in flight.
### When 30 minutes is not enough
Do not chain functions, self-invoke, or poll to fake durability. Use **Vercel Workflow**, which pauses, resumes, and keeps state for minutes to months with no duration limit, plus automatic retries and crash safety. Rough guide:
- ≤ 300s → any plan, no configuration needed
- 300–800s → Pro/Enterprise, set `maxDuration`
- 800–1800s → Pro/Enterprise, extended-duration beta, per-function config
- Beyond 30 min, or needs to survive a crash/deploy → Vercel Workflow (`workflow` skill)
Workflow steps themselves support extended function durations, so a single step can also run up to 30 minutes.
## Large Functions (bundle size)
### Standard limits
| Runtime | Uncompressed bundle limit |
|---------|---------------------------|
| Node.js, Bun, Rust, Go | 250 MB (includes runtime layers) |
| Python | 500 MB |
| Edge runtime | 1 MB Hobby / 2 MB Pro / 4 MB Enterprise, **after gzip** |
Blowing the limit fails the build with `Serverless Function has exceeded the unzipped maximum size of 250 MB`.
### Large functions — Beta
Large functions raise the uncompressed bundle ceiling to **5 GB**. This is what makes Python data/AI libraries, model weights, browser automation (Playwright/Puppeteer), image/video processing, and big backend apps deployable as Functions.
- **Runtimes**: Node.js, Bun, Python.
- **Requires Fluid Compute with Active CPU** enabled (default for new projects).
- **New projects are eligible by default.** Existing projects opt in with the `VERCEL_SUPPORT_LARGE_FUNCTIONS` environment variable, then redeploy:
```bash
vercel env add VERCEL_SUPPORT_LARGE_FUNCTIONS # value: 1 (use 0 to disable)
```
The environment variable always takes precedence over the project default, in both directions.
- **Only functions that exceed the standard limit use the large-function path** — everything under 250 MB keeps the normal, faster path, so enabling it is not a global performance trade.
- **Not supported with Secure Compute or Static IPs.**
GitHub에서 보기