Vercel: 504 timeout on serverless functions [2026 fix]
Serverless function exceeds 10-60s timeout or cold start delay. Optimize function execution time or increase memory allocation.
TL;DR
Cause: Your serverless function is exceeding Vercel's execution timeout (10s for Hobby, 60s for Pro) or taking too long to cold-start. Fix: Reduce function execution time, increase allocated memory, or split logic into smaller functions.---
Common Error Messages
Here are exact console outputs you'll see:
``` Error: Function timed out after 10.00 seconds ```
``` 504 Gateway Timeout The request took too long to complete. Vercel serverless functions have execution limits. ```
``` Lambda Runtime Error: Task timed out after 60.00 seconds ```
``` DynaTrace: Cold start exceeded threshold - 12500ms initialization time detected ```
``` ERR_HTTP_REQUEST_TIMEOUT at /api/process-data - function duration: 65432ms ```
---
Root Causes (Ranked by Frequency)
1. Database queries without connection pooling (40% of cases) 2. Large file processing synchronously (25%) 3. External API calls without timeouts (20%) 4. Memory exhaustion forcing GC pauses (10%) 5. Cold starts on low memory tiers (5%)
---
Broken Code → Fixed Code
Problem 1: Unoptimized Database Query
BROKEN: ```javascript // pages/api/get-user.js export default async function handler(req, res) { const pool = mysql.createPool({ host: 'db.example.com' }); const connection = await pool.getConnection(); // Creates new connection EVERY request - 3-5s overhead per cold start const rows = await connection.query( 'SELECT * FROM users WHERE id = ?', [req.query.id] ); res.json(rows); } ```
FIXED: ```javascript // pages/api/get-user.js import { Pool } from '@vercel/postgres';
const pool = new Pool({ connectionString: process.env.POSTGRES_URL });
export default async function handler(req, res) { // Reuse connection pool - eliminates cold start penalty const client = await pool.connect(); try { const result = await client.query( 'SELECT id, name FROM users WHERE id = $1 LIMIT 1', [req.query.id] ); res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=120'); res.json(result.rows[0] || null); } finally { client.release(); } } ```
Why it works: Connection pooling reuses TCP connections. @vercel/postgres automatically handles regional routing. ISR caching prevents repeated calls.
---
Problem 2: Blocking I/O on Large Files
BROKEN: ```javascript // pages/api/process-csv.js export default async function handler(req, res) { const file = await req.body.pipe( fs.createWriteStream('./upload.csv') ); // Entire file loaded into memory before processing const data = fs.readFileSync('./upload.csv', 'utf-8'); const rows = data.split('\n').map(row => JSON.parse(row)); res.json({ processed: rows.length }); // 40s+ for 10MB files } ```
FIXED: ```javascript // pages/api/process-csv.js import { createReadStream } from 'fs'; import { createInterface } from 'readline';
export default async function handler(req, res) { // Stream file instead of loading entirely const readable = createReadStream('./upload.csv'); const rl = createInterface({ input: readable }); let count = 0; rl.on('line', (line) => { // Process line-by-line without blocking processRow(JSON.parse(line)); count++; }); rl.on('close', () => { res.json({ processed: count }); // Completes in <2s }); } ```
Why it works: Streaming processes one chunk at a time instead of buffering. Use [background jobs with Inngest](/?guide=vercel-background-jobs) for CPU-intensive work.
---
Problem 3: External API Without Timeout
BROKEN:
```javascript
// pages/api/fetch-weather.js
const response = await fetch(
https://api.weather-service.com/forecast?city=${city}
);
// If weather API is slow, request hangs entire function
```
FIXED: ```javascript // pages/api/fetch-weather.js const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); // 5s timeout
try {
const response = await fetch(
https://api.weather-service.com/forecast?city=${city},
{ signal: controller.signal }
);
clearTimeout(timeoutId);
res.json(await response.json());
} catch (err) {
if (err.name === 'AbortError') {
res.status(504).json({ error: 'External service timeout' });
}
}
```
---
Immediate Fixes (In Priority Order)
1. Increase memory: Edit vercel.json:
```json
{ "functions": { "pages/api/**": { "memory": 3008 } } }
```
*(Note: Memory scaling beyond 3GB requires Enterprise; verify current Vercel tier)*
2. Enable ISR caching: Add Cache-Control: s-maxage=60 header to prevent re-runs.
3. Use background jobs: Move heavy work to [Vercel Cron](/?guide=vercel-cron-jobs) or external queue.
4. Check cold starts: Review [Vercel Analytics](https://vercel.com/docs/analytics) → Function Duration tab.
5. Switch databases: Use Vercel Postgres (auto-pooling) instead of raw connections.
---
Still Broken? Check These Too
middleware.ts running on every request adds 50-200ms. Scope it with matchers.vercel build --analyze to find bloat.nodeVersion in vercel.json to 20+.---
Official Resources
---
Found a different variation? Drop it in the comments—especially if you hit this on specific frameworks (Next.js 13 App Router behavior differs from Pages Router for timeouts).