Vercel: 504 timeout on serverless functions [2026 fix]
Serverless functions exceed 10s default timeout or cold start takes too long; increase function timeout and optimize initialization code.
TL;DR
Cause: Your Vercel serverless function is hitting the default 10-second timeout limit or experiencing slow cold starts due to heavy dependencies.
Fix: Increase maxDuration in your function config and optimize initialization code outside request handlers.
---
Exact Error Messages You'll See
``` Error: FUNCTION_TIMEOUT at Runtime.ExternalError at async /var/task/index.js:1:1 ```
``` 504: Gateway Timeout The request timed out. The serverless function did not respond within the timeout period. ```
``` WARN Duration: 10001.24 ms, Billed Duration: 10000 ms, Max Memory Used: 512 MB Task timed out after 10.00 seconds ```
``` Error: connect ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:18) Timeout waiting for database connection ```
``` CRITICAL_ERROR: Function initialization exceeded timeout threshold Node.js heap out of memory or blocking synchronous operations detected ```
---
Broken Code vs. Fixed Code
Problem 1: Default Timeout Too Short
BROKEN: ```javascript // api/process-data.js - NO timeout config export default async function handler(req, res) { const result = await heavyDatabaseQuery(); const processed = await expensiveComputation(result); res.status(200).json(processed); }
async function heavyDatabaseQuery() { // Takes 8-12 seconds return new Promise(resolve => setTimeout(() => resolve({}), 11000)); } ```
FIXED: ```javascript // api/process-data.js - WITH maxDuration config export const config = { maxDuration: 30, // Increased from default 10 seconds memory: 1024, // Optional: increase memory if needed };
export default async function handler(req, res) { const result = await heavyDatabaseQuery(); const processed = await expensiveComputation(result); res.status(200).json(processed); }
async function heavyDatabaseQuery() { // Now has 30 seconds to complete return new Promise(resolve => setTimeout(() => resolve({}), 11000)); } ```
Problem 2: Cold Start Bloat
BROKEN: ```javascript // api/search.js - Initialization INSIDE handler export default async function handler(req, res) { // These dependencies load on EVERY request const tf = require('@tensorflow/tfjs'); const model = await tf.loadLayersModel('file://./model.json'); const vectorDb = require('large-vector-library'); const db = new vectorDb.Client(); const results = await db.query(req.body.q); res.status(200).json(results); } ```
FIXED: ```javascript // api/search.js - Initialize OUTSIDE handler let model = null; let db = null;
// Lazy initialization on first request async function initializeServices() { if (model && db) return; const tf = require('@tensorflow/tfjs'); model = await tf.loadLayersModel('file://./model.json'); const vectorDb = require('large-vector-library'); db = new vectorDb.Client(); }
export const config = { maxDuration: 25, };
export default async function handler(req, res) { await initializeServices(); const results = await db.query(req.body.q); res.status(200).json(results); } ```
Problem 3: Connection Pool Exhaustion
BROKEN: ```javascript // api/users.js - New connection per request import { Pool } from 'pg';
export default async function handler(req, res) { const pool = new Pool({ connectionString: process.env.DATABASE_URL, }); const client = await pool.connect(); const result = await client.query('SELECT * FROM users'); await client.release(); res.status(200).json(result.rows); } ```
FIXED: ```javascript // api/users.js - Reuse connection pool import { Pool } from 'pg';
let pool = null;
function getPool() { if (!pool) { pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 5, // Limit connections idleTimeoutMillis: 30000, }); } return pool; }
export const config = { maxDuration: 15, };
export default async function handler(req, res) { try { const pool = getPool(); const result = await pool.query('SELECT * FROM users'); res.status(200).json(result.rows); } catch (error) { res.status(500).json({ error: error.message }); } } ```
---
Still Broken? Check These Too
1. Memory Limits: If Memory Used: 512 MB shows near limit, increase via config.memory (max 3008 MB on Pro plans). Check [function memory optimization guide](/?guide=vercel-memory).
2. Slow Third-Party APIs: Your function is waiting on external services (Stripe, SendGrid, etc.). Add timeout wrappers: Promise.race([apiCall(), timeout(8000)]).
3. Bundle Size Bloat: Large node_modules cause slow cold starts. Audit with vercel build --debug and check [dependency optimization](/?guide=bundle-analysis).
---
Version Notes
I'm confident about the config.maxDuration API as of 2024, but Vercel occasionally adjusts timeout limits on different plan tiers. Verify your plan limits at: https://vercel.com/docs/functions/serverless-functions/runtimes#max-duration
Pro and Enterprise plans support maxDuration up to 900 seconds; Hobby plans cap at 60 seconds.
---
Found a different variation? Drop it in the comments.
Did you hit a 504 from a different root cause (streaming responses, WebSocket timeouts, etc.)? Help others by sharing below.