A Vercel serverless function timeout happens because maxDuration defaults to 15 seconds on Serverless Functions — the Pro plan raises the ceiling, not the default. Any request that runs past the limit is killed by the platform and returns a 504.
TL;DR: add a functions block to vercel.json setting maxDuration, or export maxDuration from the route itself. Full config below.

Problem:
Application is using Page router and there are SSR API requests runs on each deploy and after each caching expires cycle
The API requests takes sometimes more than 30 seconds to fetch all the data
Vercel infrastructure Serverless Functions Execution Duration is 15 seconds although the plan is PRO!

So sometimes getting 504 error:

Why the Pro plan still times out at 15 seconds
This is the part that catches most people out. The number advertised with your plan is the maximum you are allowed to configure, not the value your functions actually run with. Every Serverless Function starts from the same conservative default, and upgrading your plan does not change it. Until you set maxDuration explicitly, a Pro project behaves exactly like a Hobby one.
When the limit is hit, the function is terminated mid-execution. Your logs may show no application-level error at all — the work simply stops, and Vercel's edge returns 504 GATEWAY_TIMEOUT to the browser. That mismatch between "no error in my code" and "504 in production" is the usual symptom.
Solution:
Setting maxDuration of Serverless Functions Execution Duration by:
- Create vercel.json file in the root folder of the project
- If you use page router use pages/**/* pattern
- Add code below to vercel.json file:
{
"functions": {
"pages/**/*": {
"maxDuration": 300
}
}
}
Now the "Serverless Functions Execution Duration" will be 300 seconds (5 minutes)
Note that:
"Hobby" plan has max 10 seconds,
"Pro" plan has max up to 300 seconds and
"Enterprise" plan can be up to 900 seconds
(these numbers posted in this blog on 12 December 2023, and maybe changed in the future)
Setting maxDuration per route instead of globally
The vercel.json approach applies one value to every matching path. If only one or two endpoints are slow, it is cleaner to raise the limit just for those, so a runaway request elsewhere still fails fast.
In the App Router, export the value directly from the route file:
// app/api/report/route.ts
export const maxDuration = 300;
export async function GET() {
// ...slow work
}
In the Pages Router, the equivalent glob targets the API directory only:
{
"functions": {
"pages/api/report.ts": {
"maxDuration": 300
}
}
}
When raising the limit is the wrong fix
A 300-second budget makes the 504 disappear, but a user staring at a blank page for five minutes has not been helped. Raising maxDuration buys you room; it does not make the request fast. Worth considering alongside it:
- Cache the expensive call. If the data changes on a schedule rather than per request, ISR or a revalidating fetch means only the first visitor after expiry pays the cost.
- Parallelise the fetches. Serial
awaitcalls in a loop are the most common cause of a 30-second SSR request.Promise.alloften collapses it dramatically. - Stream the response. Sending partial output keeps the connection alive and gets content in front of the user sooner.
- Move the work off the request path. A cron job or background task that writes results somewhere the page can read cheaply removes the timeout question entirely.
Frequently asked questions
Why do I get a 504 when my function works locally?
Locally there is no execution-duration limit, so a request that takes 30 seconds simply takes 30 seconds. On Vercel the same request is terminated at the configured maxDuration, and the platform returns a 504 in its place.
Does maxDuration apply to Edge Functions?
No. Edge Functions run on a different runtime with its own constraints. The maxDuration setting described here applies to Serverless Functions.
Do I need to redeploy after changing vercel.json?
Yes. vercel.json is read at build time, so the new limit only takes effect on the next deployment.
Plan limits change over time — always confirm the current ceiling in the Vercel functions duration documentation before relying on a specific number. For a related performance write-up, see The Hidden Clock: When Code Leaks Secrets.
Comments