Vercel: 504 timeout on serverless functions [2026 fix]

Serverless function exceeds 10s timeout or cold starts fail. Increase function timeout, optimize code, or split into smaller functions.

Vercel: 504 timeout on serverless functions [2026 fix]

TL;DR

Cause: Your serverless function exceeded Vercel's execution timeout (10 seconds default) or failed during cold start initialization. Fix: Increase timeout in vercel.json, optimize database queries, or migrate heavy processing to background jobs.

---

Real Console Error Messages

Here are exact error outputs you'll see:

``` 504 Gateway Timeout The request took too long to process and was terminated. Request ID: abc123def456 Duration: > 10000ms ```

``` [ERROR] RequestId: xyz789abc123 Task timed out after 10.01 seconds FATAL Error: Lambda execution timeout exceeded ```

``` 504 Service Unavailable Upstream request timeout Vercel Function Error: FUNCTION_INVOCATION_TIMEOUT Elapsed: 10012ms ```

``` ERROR Function crashed Timeout waiting for function to respond Status: 504 Duration exceeded: 10 seconds ```

``` Cannot GET /api/process Error: The function execution has timed out (10s). Trace: at FunctionTimeout (runtime) ```

---

The Problem (Broken Code)

```javascript // ❌ BROKEN: Database query takes 15+ seconds export default async function handler(req, res) { try { // Unoptimized query with 3 nested joins const result = await db.query(` SELECT users.*, orders.*, products.* FROM users JOIN orders ON users.id = orders.user_id JOIN products ON orders.product_id = products.id WHERE users.status = 'active' `); // Processing takes 8+ seconds const processed = result.map(item => { return heavyCalculation(item); // CPU-intensive }); res.status(200).json(processed); } catch (err) { res.status(500).json({ error: err.message }); } } ```

---

The Fix (Side by Side)

Fix #1: Increase Timeout + Optimize Query

Step 1: Update vercel.json

```json { "functions": { "api/process.js": { "maxDuration": 30 } } } ```

Step 2: Optimize the function

```javascript // ✅ FIXED: Paginated query + indexed fields export default async function handler(req, res) { res.setHeader('Content-Type', 'application/json'); try { // Use pagination to limit dataset const page = parseInt(req.query.page) || 1; const limit = 50; const offset = (page - 1) * limit; // Only select needed fields const result = await db.query(` SELECT users.id, users.name, orders.total FROM users JOIN orders ON users.id = orders.user_id WHERE users.status = $1 LIMIT $2 OFFSET $3 `, ['active', limit, offset]); // Process in batches or move to background job const processed = await Promise.all( result.map(item => cachedHeavyCalculation(item)) ); res.status(200).json({ data: processed, page, hasMore: processed.length === limit }); } catch (err) { console.error('Function error:', err); res.status(500).json({ error: 'Processing failed' }); } } ```

Fix #2: Move Heavy Work to Background Job

```javascript // ✅ FIXED: Return immediately, process async import { queue } from '@vercel/functions';

export default async function handler(req, res) { try { const jobId = crypto.randomUUID(); // Queue task instead of processing inline await queue.enqueue({ name: 'heavy-processing', jobId, data: req.body }); // Return immediately res.status(202).json({ message: 'Processing started', jobId }); } catch (err) { res.status(500).json({ error: err.message }); } } ```

Fix #3: Add Connection Pooling

```javascript // ✅ FIXED: Reuse database connections import { Pool } from 'pg';

const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 20, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000 });

export default async function handler(req, res) { const client = await pool.connect(); try { const result = await client.query('SELECT ...'); res.status(200).json(result.rows); } finally { client.release(); } } ```

---

Still broken? Check these too

1. Cold Start Issues — New functions load slowly. Enable [Vercel's prerender option](/?guide=vercel-cold-starts) or keep functions warm with scheduled requests.

2. Memory Constraints — Functions limited to 512MB-3008MB depending on plan. Check memory usage with console.time() and optimize large data processing.

3. Environment Variables Loading — Slow secret retrieval can timeout. Verify DATABASE_URL and credentials load within 1 second using console.time('env-load').

---

Official Resources

  • [Vercel Functions Documentation](https://vercel.com/docs/functions/introduction)
  • [Timeout Configuration Guide](https://vercel.com/docs/functions/configuring-functions)
  • [Related: Database Connection Timeouts](/?guide=database-timeouts)
  • ---

    Checklist Before Deployment

  • [ ] Set maxDuration in vercel.json (test with 30s first)
  • [ ] Database queries return in <5 seconds (use EXPLAIN ANALYZE)
  • [ ] External API calls have 3-second timeout fallback
  • [ ] No N+1 queries (load related data in single query)
  • [ ] Response size <6MB uncompressed
  • ---

    Found a different variation? Drop it in the comments below — include your error message and what fixed it for you.

    🔥 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