Function limits
The platform ceilings that apply to every Function, and the status code behind each rejected request.
These are platform ceilings: they apply to every Function on every plan and cannot be raised in configuration. Quotas that do change with your plan, including per-Function memory and Concurrency, live in Limits and billing.
Ceilings
| Limit | Value |
|---|---|
| Request headers | 64 KiB total |
| Request body | 6 MiB |
| Response body per invocation | 32 MiB |
| Invocation duration | 1 second to 28800 seconds (8 hours), default 30 seconds |
| Memory per Function | 128 MB to 3009 MB declared, raised to 256 MB minimum |
| vCPU per Function | 1, not configurable |
| Requests per copy of a Function | 32 |
| WebSocket connections per copy | 250 per 256 MB of memory |
| WebSocket connection lifetime | max_duration, capped at 4 hours |
| WebSocket idle close | 15 minutes with no bytes in either direction |
A request whose headers exceed 64 KiB is answered with 431 before your code runs. A body above 6 MiB never reaches your code either; a handler-style Function answers it with 413. The response ceiling is set higher than the request ceiling on purpose, so that server-rendered pages and large JSON responses are not cut off. Response bytes are forwarded as they are produced, which makes 32 MiB a bound on one invocation rather than on a buffer.
WebSocket traffic does not pass through the request-body path, so the 6 MiB figure does not apply to frames on an open connection.
What a rejected request looks like
Every rejection in the following table renders a branded error page that prints its errorCode next to the request ID, so a screenshot from a visitor is enough to identify which condition fired. Pair it with request logs to find the invocation.
| Status | errorCode | Condition |
|---|---|---|
| 429 | EDGE_FUNCTION_CONCURRENCY_LIMIT | The plan's Concurrency for this Function is fully in use |
| 503 | EDGE_FUNCTION_AT_CAPACITY | Every copy is busy and new capacity did not arrive in time |
| 503 | EDGE_FUNCTION_RESUMING | The Function is finishing an idle transition |
| 503 | EDGE_FUNCTION_STARTING | The copy a sticky URL points at is still starting |
| 503 | EDGE_FUNCTION_UNAVAILABLE | Temporarily unavailable for another reason |
| 503 | EDGE_ORGANIZATION_COMPUTE_LIMIT | The organization is at its compute limit or its billing cap |
| 503 | EDGE_FUNCTION_START_FAILED | The Function could not be started |
| 503 | EDGE_FUNCTION_NOT_READY | The Function could not be prepared to run |
| 502 | EDGE_FUNCTION_UNREACHABLE | The Function could not be reached |
| 504 | EDGE_FUNCTION_TIMEOUT | The invocation exceeded max_duration before sending headers |
| 501 | EDGE_HANDLER_UNSUPPORTED | The matched route points at a handler this deployment cannot serve |
| 500 | EDGE_ROUTE_MISCONFIGURED | The matched route is incomplete |
| 403 | EDGE_STICKY_SESSION_REJECTED | The sticky URL is invalid, expired, or bound to another route |
EDGE_FUNCTION_CONCURRENCY_LIMIT, EDGE_FUNCTION_AT_CAPACITY, EDGE_FUNCTION_RESUMING and EDGE_FUNCTION_STARTING carry Retry-After: 2, because each of them clears on its own within seconds. The rest need a change from you: a code fix, a config fix, or a plan change.
A 429 is the one to watch for in production, since it means real traffic is being turned away rather than queued. Concurrency covers how the limit is counted and what raises it.
