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.

πŸ”₯ 0d
LIVE
↓ PlanetScale rage spiking β€’βš  Vercel pricing complaints ‒↑ Railway gaining fast ‒↑ Supabase happiness rising ‒↑ Resend loved by devs ‒↓ PlanetScale rage spiking β€’βš  Vercel pricing complaints ‒↑ Railway gaining fast ‒↑ Supabase happiness rising
DEVELOPER PAIN RADAR // Loading...

Developers complain.
Opportunities appear.

We track what developers are struggling with today β€” and what opportunities that creates.

β€”
guides today
β€”
avg happiness
πŸ”₯ Pain
πŸ“– Guides
πŸ”­ Explore
πŸ‘€ Mine
πŸ”₯ Pain Radar β€” rage scores today
β†— share
πŸ’‘ Opportunity Feed β€” pain = market gap
πŸ“ˆ Tool Momentum
all scores β†’
πŸ“– Latest Guide
all guides β†’
πŸ“– All Guides
πŸ“Š Tool Scores
+ Submit
πŸ“° Hacker News
βž• Submit a Tool
← back