Vercel: 504 timeout on serverless functions [2026 fix]
504 Gateway Timeout means your function exceeded 10s (Pro) or 60s (Enterprise) execution limit. Reduce payload size, optimize database queries, or increase function timeout.
Vercel: 504 Timeout on Serverless Functions [2026 Fix]
TL;DR
Cause: Your serverless function exceeded Vercel's execution timeout (10 seconds on Hobby/Pro, 60 seconds on Enterprise). Fix: Optimize slow operations, reduce payload parsing, or upgrade to Enterprise for longer timeouts.---
Real Console Error Messages
Error 1: Vercel Logs Dashboard
``` ErrorCode: FUNCTION_INVOCATION_TIMEOUT Duration: 10023ms Status: 504 Message: "Gateway Timeout - The serverless function did not complete before the timeout of 10000 milliseconds." ```Error 2: Browser Network Tab
``` GET /api/process-order HTTP/1.1 Status: 504 Gateway Timeout Time: 10.2s Content-Length: 0 ```Error 3: Next.js Function Logs
``` [Error] Function failed: timeout at processRequest (/var/task/api/orders.js:45:12) at Runtime.handler (/var/task/index.js:1:1) Duration: 10024 ms ```Error 4: CloudWatch (Enterprise)
``` { "errorMessage": "Task timed out after 60.00 seconds", "errorType": "TimeoutError", "stackTrace": ["Runtime.handler"] } ```Error 5: Client-Side Error Response
``` Fetch Error: 504 Gateway Timeout URL: https://example.com/api/generate-report Headers: {"x-vercel-id": "sfo1::abcd1-1234567890"} ```---
Broken Code → Fixed Code
Problem 1: Unoptimized Database Queries
BROKEN: ```javascript // api/getUserData.js - This queries 100+ records sequentially export default async function handler(req, res) { const userId = req.query.id; // Fetches user, then all orders, then all invoices serially const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]); const orders = await db.query('SELECT * FROM orders WHERE user_id = ?', [userId]); const invoices = await db.query('SELECT * FROM invoices WHERE user_id = ?', [userId]); const payments = await db.query('SELECT * FROM payments WHERE user_id = ?', [userId]); res.json({ user, orders, invoices, payments }); } ```
FIXED: ```javascript // api/getUserData.js - Parallel queries + pagination export default async function handler(req, res) { const userId = req.query.id; const limit = 50; // Paginate results // Run queries in parallel, not serially const [user, orders, invoices] = await Promise.all([ db.query('SELECT * FROM users WHERE id = ?', [userId]), db.query('SELECT * FROM orders WHERE user_id = ? LIMIT ?', [userId, limit]), db.query('SELECT * FROM invoices WHERE user_id = ? LIMIT ?', [userId, limit]) ]); res.json({ user, orders, invoices, pagination: { limit } }); } ```
Problem 2: Large Payload Processing
BROKEN: ```javascript // api/process-csv.js - Loads entire file into memory export default async function handler(req, res) { const fileData = await req.body.text(); // 50MB+ string in memory const rows = fileData.split('\n'); rows.forEach(row => { // Process each row - takes 15+ seconds complexCalculation(row); }); res.json({ processed: rows.length }); } ```
FIXED:
```javascript
// api/process-csv.js - Stream + background job
export default async function handler(req, res) {
const jobId = generateId();
// Queue background job, return immediately
queueJob({
type: 'PROCESS_CSV',
jobId,
fileUrl: req.body.fileUrl
});
res.json({ jobId, status: 'queued', checkStatusUrl: /api/job-status?id=${jobId} });
}
// processes/csv-worker.js - Runs async, streamed processing export async function processCsvJob(fileUrl) { const stream = fs.createReadStream(fileUrl); let count = 0; for await (const chunk of stream) { complexCalculation(chunk); count++; } return count; } ```
Problem 3: External API Calls Without Timeout
BROKEN: ```javascript // api/send-emails.js - No timeout on external calls export default async function handler(req, res) { const emails = req.body.recipients; // If email service hangs, this blocks forever const results = await Promise.all( emails.map(email => fetch('https://slow-email-service.com/send', { method: 'POST', body: JSON.stringify({ to: email }) }) ) ); res.json({ sent: results.length }); } ```
FIXED: ```javascript // api/send-emails.js - Timeouts + queue pattern export default async function handler(req, res) { const emails = req.body.recipients; // Queue emails, return immediately const jobId = await emailQueue.enqueue(emails); res.json({ jobId, status: 'queued' }); }
// Worker with timeouts async function sendEmailWithTimeout(email, timeoutMs = 5000) { return Promise.race([ fetch('https://email-service.com/send', { method: 'POST', body: JSON.stringify({ to: email }) }), new Promise((_, reject) => setTimeout(() => reject(new Error('Email timeout')), timeoutMs) ) ]); } ```
---
Still Broken? Check These Too
1. Cold Start + Slow Dependencies – Large npm packages (e.g., sharp, pdf-lib) trigger long cold starts. Use @vercel/og or lightweight alternatives. [See cold starts guide](/?guide=vercel-cold-starts).
2. Memory Limits – Functions exceeding 3GB RAM may get killed. Check function logs for OOM (Out of Memory) errors. Reduce in-memory caching; use Redis instead.
3. Regions/Edge Function Issues – If using Edge Functions, they have 30-second limit (not 10/60). Switch to Serverless Functions or restructure as Edge Middleware. [See Edge vs Serverless](/?guide=edge-serverless-comparison).
---
Prevention Checklist
vercel dev and measure execution timeAbortController for external requests---
Official Resources
---
Found a different variation of this 504 timeout? Drop it in the comments—we update this guide monthly.