Vercel: 504 timeout on serverless functions [2026 fix]
Serverless function exceeds 10s timeout or cold starts pile up. Increase function timeout and optimize initialization code.
Vercel: 504 timeout on serverless functions [2026 fix]
TL;DR
Cause: Your serverless function execution time exceeds Vercel's 10-second default timeout, or cold starts are delayed by heavy dependencies. Fix: SetmaxDuration in vercel.json and defer non-critical initialization outside the handler.---
Real Console Error Messages
``` 1. "504 Gateway Timeout" in browser console Request to /api/process timed out after 10.00s
2. Vercel Function Logs: FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory Function duration: 10001ms (exceeded limit)
3. CloudWatch equivalent: "errorMessage": "Task timed out after 10.00 seconds"
4. Client-side network tab: 504 Service Unavailable Content-Length: 0 X-Vercel-Id: sfo1::abcd1-1234-5678
5. Vercel Dashboard: "Function 'api/process' exceeded maximum duration of 10s" ```
---
Code: Broken vs. Fixed
❌ BROKEN: Timeout on Initialization
```javascript // api/process.js - DEFAULT BEHAVIOR (10s limit) import heavyDependency from 'some-massive-lib'; import anotherLib from 'another-slow-lib';
// This runs on EVERY invocation const client = heavyDependency.initialize(); const config = anotherLib.loadSync(); // blocking!
export default async function handler(req, res) { const result = await client.query(req.body); res.status(200).json({ result }); } ```
Problem: Dependencies load synchronously on every cold start. Database queries, file I/O, and initialization easily exceed 10 seconds.
---
✅ FIXED: Lazy Loading + Extended Timeout
Step 1: Update vercel.json
```json
{
"functions": {
"api/process.js": {
"maxDuration": 30,
"memory": 1024
}
}
}
```
Step 2: Refactor handler with lazy initialization ```javascript // api/process.js - OPTIMIZED let client = null; let config = null;
// Lazy load: only initialize once, cache the result async function initializeClient() { if (!client) { const heavyDependency = await import('some-massive-lib'); client = await heavyDependency.initialize(); } return client; }
async function loadConfig() { if (!config) { const anotherLib = await import('another-slow-lib'); config = await anotherLib.load(); // async, not blocking } return config; }
export default async function handler(req, res) { try { const client = await initializeClient(); const cfg = await loadConfig(); const result = await client.query(req.body); res.status(200).json({ result }); } catch (error) { console.error('Function error:', error); res.status(500).json({ error: 'Processing failed' }); } } ```
Why this works:
---
Version Notes
I'm explicitly uncertain about: Vercel's exact timeout handling changed between 2024-2026 builds. Pro plan functions may support up to 60 seconds; verify your account tier in Settings → Functions. Confirm with vercel env pull && cat .env.production.local for runtime environment variables.
---
Still Broken? Check These Too
1. Memory exhaustion: Monitor function logs for "Allocation failed" messages. Increase memory in vercel.json from 512MB to 1024MB or 3008MB. [Related: Memory optimization guide](/?guide=vercel-memory).
2. Cold start chains: If calling multiple APIs sequentially inside your function, batch requests or use Promise.all(). Each network call adds 100-500ms.
3. Database connection pooling: Connections to RDS/PostgreSQL without pooling create new TCP sockets on each invocation. Use node-postgres with a connection pool or Prisma's poolingMode: "transaction". [Related: Database connection patterns](/?guide=db-pooling).
---
Verification Checklist
maxDuration set to ≥20s in vercel.json (adjust based on your plan limits)await import() instead of import at top levelvercel dev locally to simulate cold starts---
Official Documentation
[Vercel Serverless Functions API Reference](https://vercel.com/docs/functions/serverless-functions)
---
Found a different variation? Drop it in the comments—2am emergencies need crowd-sourced wisdom.