Vercel: 504 timeout on serverless functions [2026 fix]

Serverless function exceeds 10s timeout limit or cold start hangs. Increase function timeout, optimize code, or split into smaller functions.

TL;DR

Cause: Your serverless function is taking longer than Vercel's default 10-second timeout (or your configured limit) to respond.

Fix: Increase the maxDuration setting in vercel.json or your function configuration, optimize slow database queries, and implement caching.

---

Real Console Error Messages

``` ERROR: 504 Gateway Timeout Connection timeout after 10000ms ```

``` [FUNCTION_INVOCATION_TIMEOUT] Your serverless function exceeded the maximum execution time of 10 seconds ```

``` Error: Task timed out after 10.00 seconds ```

``` FETCH_TIMEOUT: The request to your function endpoint timed out at Runtime.invokeFunction (internal/serverless:1234) ```

``` 504 Service Unavailable The server did not respond within the specified timeout period. ```

---

Broken Code vs. Fix

Problem 1: Default Timeout Too Low

Broken: ```javascript // pages/api/generate-report.js export default async function handler(req, res) { const data = await fetchLargeDataset(); const processed = await heavyProcessing(data); const pdf = await generatePDF(processed); res.status(200).json({ url: pdf }); } ```

Fixed: ```javascript // pages/api/generate-report.js export default async function handler(req, res) { const data = await fetchLargeDataset(); const processed = await heavyProcessing(data); const pdf = await generatePDF(processed); res.status(200).json({ url: pdf }); }

// vercel.json export const config = { maxDuration: 60 }; ```

Problem 2: Synchronous Processing in Cold Start

Broken: ```typescript // pages/api/process.ts export default async function handler(req: NextApiRequest, res: NextApiResponse) { const users = await db.query('SELECT * FROM users WHERE status = ?', ['active']); users.forEach(user => { expensiveCalculation(user); }); res.json({ processed: users.length }); } ```

Fixed: ```typescript // pages/api/process.ts import { Ratelimit } from '@upstash/ratelimit';

const ratelimit = new Ratelimit({ ... });

export const config = { maxDuration: 30 };

export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { success } = await ratelimit.limit('process'); if (!success) return res.status(429).json({ error: 'Rate limited' }); // Fetch only required columns const users = await db.query( 'SELECT id, name FROM users WHERE status = ? LIMIT 100', ['active'] ); // Queue heavy processing for background job await queue.enqueue({ type: 'batch_process', userIds: users.map(u => u.id) }); res.json({ queued: users.length }); } ```

Problem 3: Missing Connection Pooling

Broken: ```javascript // pages/api/users.js const mysql = require('mysql2/promise');

export default async function handler(req, res) { const connection = await mysql.createConnection({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASS, database: process.env.DB_NAME }); const [rows] = await connection.query('SELECT * FROM users'); await connection.end(); res.json(rows); } ```

Fixed: ```javascript // lib/db.js import mysql from 'mysql2/promise';

let pool;

export async function getPool() { if (!pool) { pool = await mysql.createPool({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASS, database: process.env.DB_NAME, waitForConnections: true, connectionLimit: 5, queueLimit: 0 }); } return pool; }

// pages/api/users.js import { getPool } from '@/lib/db';

export const config = { maxDuration: 15 };

export default async function handler(req, res) { const pool = await getPool(); const [rows] = await pool.query('SELECT id, name FROM users LIMIT 50'); res.json(rows); } ```

---

Still Broken? Check These Too

1. Cold start delays – Your function dependencies (like heavy npm modules) are too large. Use dynamic imports: const heavy = await import('heavy-lib') to defer loading.

2. External API timeouts cascading – If you're calling third-party APIs inside your function, they're timing out. Implement AbortController with 5s timeout: const controller = new AbortController(); setTimeout(() => controller.abort(), 5000);

3. Memory exhaustion causing slowness – Check CloudWatch/Vercel Analytics. If memory usage spikes near the limit, either upgrade to Pro plan for more RAM or optimize data structures. See [memory optimization guide](/?guide=vercel-memory).

---

Configuration Notes

  • Standard plan: Max 10 seconds (hard limit)
  • Pro plan: Max 60 seconds (adjustable via maxDuration)
  • Enterprise: Custom limits available
  • We cannot confirm if 2026 Vercel versions support custom timeouts beyond 60 seconds – check the [official Vercel serverless function limits documentation](https://vercel.com/docs/functions/serverless-functions#function-timeout).

    ---

    Related Issues

    Check [Cold start optimization strategies](/?guide=vercel-cold-start) and [Database connection pooling for serverless](/?guide=serverless-db-pool).

    ---

    Found a different variation? Drop it in the comments.

    🔥 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