How do I fix a slow server response (high TTFB)?
A slow server response usually shows up as a high Time to First Byte (TTFB), the gap between a navigation starting and the first byte of the response arriving. Because that byte comes before any markup, every later metric waits behind it. This page explains what the number actually contains, what “good” looks like, and how to bring it down.
Why this matters
TTFB is not a single server stopwatch. web.dev breaks it into the phases a request passes through: redirect time, service worker startup, DNS lookup, connection and TLS negotiation, and finally the request itself up to the point the first byte arrives. Any one of those can dominate. A redirect chain, a cold connection, a slow DNS answer or a heavy database query all inflate the same number, which is why the fix depends on which phase is responsible. The stakes are high because TTFB sits upstream of First Contentful Paint and Largest Contentful Paint; if the server takes two seconds to say anything, the page cannot paint in under two seconds no matter how small the assets are. web.dev’s rough guide is that most sites should aim for a TTFB of 0.8 seconds or less, with values above 1.8 seconds considered poor. It stresses that these thresholds are guidance, not a Core Web Vital: a server-rendered site can tolerate a higher TTFB and still paint quickly, while a single-page app that ships an empty shell and fills it with JavaScript feels the latency far more.
How to fix it
Start by measuring, then attack the largest phase. web.dev stresses that reducing connection setup time and backend processing time is what lowers TTFB, so the levers are fewer round trips and less work per request. Collapse redirect chains, because redirect time is counted inside the metric, and enable compression so the response body leaves faster once the first byte has been produced. Putting a cache or edge network in front of the origin lets repeat requests skip the back end entirely.
# Time the first byte directly with curl
curl -o NUL -s -w "time_starttransfer: %{time_starttransfer}s\n" https://example.com
// Measure navigation TTFB in the browser with the Navigation Timing API
new PerformanceObserver((entryList) => {
const [pageNav] = entryList.getEntriesByType('navigation');
console.log(`TTFB: ${pageNav.responseStart}`);
}).observe({ type: 'navigation', buffered: true });
How to verify the fix
Use a repeatable measurement rather than a single click. The curl timing above isolates server and connection overhead for one request, while the Navigation Timing snippet reports what real visitors experienced in the browser. For field data across many real users, web.dev points to the Chrome User Experience Report and the web-vitals library; those give the 75th percentile picture you actually want to optimise.
curl -o NUL -s -w "%{time_starttransfer}\n" https://example.com
Automated check
The automated check times a request to your app and reports Slow response as a Medium-severity finding when it exceeds 1000 ms, escalating to Very slow response as High above 3000 ms. These thresholds are deliberately looser than the 0.8 second target from web.dev so that clearly broken backends surface first. The result is a single probe rather than field data, so confirm anything borderline with real-user measurements before you act on it.
Scan your app free →