Blog
4 min read

504 Gateway Timeout: What It Means and How to Fix It

A 504 means the proxy in front of your app (Nginx, Cloudflare, a load balancer) gave up waiting for a response. The usual causes — slow database queries, long tasks done in the request, external APIs, timeouts set too low — and how to find and fix each.

504 Gateway Timeout means: the server in front of your app — a reverse proxy like Nginx or Caddy, Cloudflare, or a load balancer — forwarded the request to your app and gave up waiting for the answer.

Your app might still be working on it. It just took longer than the proxy was willing to wait. (Reverse proxies explained)

504 vs 502

Code The proxy is saying
502 Bad Gateway "The app gave me no valid answer" — crashed, refused, wrong port
504 Gateway Timeout "The app took too long"

A 502 points at a dead or unreachable app. A 504 points at a slow one.

Typical timeouts

  • Nginx: proxy_read_timeout defaults to 60 seconds.
  • Cloudflare: about 100 seconds on most plans, then it shows its own 524 timeout page.
  • Serverless platforms: function limits, often 10–60 seconds depending on plan.
  • Load balancers: commonly 60 seconds.

If a request regularly takes close to a minute, something is wrong — users won't wait that long either.

Cause 1: a slow database query

The most common cause. A query that was fast with 100 rows takes 40 seconds with 2 million because it's scanning the whole table.

Cause 2: long work done inside the request

Generating a big report, processing a video, sending 5,000 emails, calling an AI model several times — these don't belong in a web request.

Move them to a background job: the request starts the job and returns immediately; the user is notified (or the page polls) when it's done. (Background jobs)

Cause 3: a slow external API

Your app calls a payment provider, an AI model or another service, and that service is slow or down. Your request waits with it.

Cause 4: the server is overloaded

Too many requests at once, not enough CPU or memory, or the database's connections are all in use, so new requests queue. Check CPU and memory graphs during the slowdown. (Load testing, Postgres connection pooling)

Cause 5: the app hangs

A bug — an unresolved promise, a deadlock, an infinite loop — means the request never finishes. The app's logs will show the request starting but not ending.

How to find which it is

  1. Reproduce and time it from the server itself, bypassing the proxy:

    time curl -s -o /dev/null http://127.0.0.1:3000/slow-page
    

    (What is curl?)

  2. Check the app's logs around that time for slow queries or errors.

  3. Check the database for long-running queries:

    SELECT pid, now() - query_start AS duration, query
    FROM pg_stat_activity
    WHERE state = 'active'
    ORDER BY duration DESC;
    
  4. Check server resources — top or htop for CPU and memory.

Should you just raise the timeout?

Sometimes, briefly — for a known slow admin export, say:

location /admin/export {
    proxy_pass http://127.0.0.1:3000;
    proxy_read_timeout 300s;
}

But raising timeouts usually hides the problem. Fix the slow part, or move the work to the background.

The summary

  • 504 = the proxy waited too long for your app.
  • Usually a slow query, long work in the request, or a slow external service.
  • Measure from the server, read the logs, check the database.
  • Fix the slowness; use background jobs for long tasks.

EasySpawn runs your app, its database and a background worker on one server, with logs and resource graphs close at hand — and Claude Code can find the slow query for you. See how it works or join the waitlist.

Related: 502 Bad Gateway · Why Is My Website Slow? · HTTP Status Codes Explained · Your App Needs Background Jobs

Keep reading