How to reduce server response time (TTFB)

A slow first response holds back every speed number. How to find where your server loses time, and the fixes in order: cache, database, outside calls, capacity.

IntermediateHow-to9 min readUpdated October 30, 2026

In this guide
  1. What the number means
  2. Step 1: measure the server's share
  3. Fix 1: stop building the page every time
  4. Fix 2: make the work cheaper
  5. Fix 3: stop waiting on other services
  6. Fix 4: give the server enough room
  7. Fix 5: shorten the distance and skip the extras
  8. Where to look first on each platform
  9. Check that the fix worked
  10. Mistakes to avoid
  11. Check your own page
  12. Sources

What the number means

In Lighthouse 13.5, server response time is one of three checks in the insight called Document request latency. The check fails when the server takes more than 600 milliseconds to start responding to the request for your page. The other two checks in that insight are about redirects and compression.

The source code explains where 600 comes from. The throttling that Lighthouse uses means it cannot see a server response faster than about 570 milliseconds, so the failure line sits at 600 to avoid false alarms. The comment in the code says the real aim is 100 milliseconds. When the check fails, the saving that Lighthouse reports is the time above 100 milliseconds, which is why the estimate can look large.

This number is only the server's share. The full time to first byte also includes redirects, the address lookup and the connection. Lighthouse sets its limit at 600 milliseconds, below the 800 that counts as good for real visitors, for that reason. A page can pass here and still have a slow first byte for visitors far away. For them, see what a CDN does.

Step 1: measure the server's share

Test the page you care about, several times, and write the numbers down. This command prints the server's wait for five requests in a row:

for i in 1 2 3 4 5; do
  curl -s -o /dev/null -w '%{time_pretransfer} %{time_starttransfer}\n' https://example.com/ \
    | awk '{ printf "server wait: %d ms\n", ($2 - $1) * 1000 }'
done

It works because curl's time_starttransfer includes everything up to the moment the transfer was about to begin (time_pretransfer), plus the time the server needed to calculate the result. The difference is the server's wait.

Now read the pattern in the numbers.

What you seeWhat it usually means
The first request is slow, the next ones are fastA cache fills on the first visit. If lifetimes are short or the cache is cleared often, many visitors still get the slow one
Every request is slow, by about the same amountThe page is built from scratch each time, or the server is slow
The numbers jump aroundA busy or shared server, background jobs, or too few workers
Slow only when logged in, or in the cartThese pages skip the page cache by design
Slow only on certain pagesWork that only those pages do: a heavy query, a plugin, an outside call
A delay of nearly the same size every time, such as 5 secondsA timeout: the page is waiting for a service that does not answer

To see which part of the build is slow, have your code report it with the Server-Timing header. The time to first byte guide shows how. A performance monitoring service for applications can do the same job without code changes.

Fix 1: stop building the page every time

A dynamic site such as WordPress runs code and asks the database questions to build every page. A page cache saves the finished HTML and sends it back for the next request. It is the largest gain for most sites, and the first thing to check.

On WordPress, a page cache works like this. If the setting WP_CACHE is on and a file called advanced-cache.php exists in the content folder, WordPress loads that file very early in start-up, before most of its own code runs. That is how a caching plugin can return a saved page without waking up the rest of WordPress. Many hosts do the same job at the server level. Ask your host what it provides before you add a plugin, because two page caches can fight each other.

Decide what must not be cached:

For pages that change often, even a short cache helps. web.dev notes that on a busy site only the first visitor in each cache period waits for the full trip to the server, and that caching a dynamic page for a few seconds can cut the load noticeably with little effect on freshness. A site that is mostly static can go further and build its pages ahead of time, so there is nothing to compute at request time.

See caching explained for the other layers, and HTTP caching headers to set the lifetimes.

Fix 2: make the work cheaper

When a page cannot be cached, make building it cheaper.

Use a current PHP version, with OPcache on. For PHP sites, OPcache stores the compiled form of each script in shared memory, so PHP does not load and parse the scripts again on every request. It has been bundled with PHP since version 5.5. Ask your host that it is enabled and that the PHP version is still supported.

Add a persistent object cache. WordPress has an object cache, but by default it lives only for the length of one request, so nothing is remembered for the next. A persistent one, such as Redis or Memcached, keeps database results and settings in memory between requests. It is installed through a file named object-cache.php in the content folder. WordPress's Site Health screen tests for this. It recommends a persistent object cache when the site is a multisite network, has more than 500 autoloaded options or more than 100,000 bytes of them, or has 1,000 or more comments, options, posts, terms or users. Drupal's advice from Lighthouse is the same in spirit: PHP opcode caching, and memory caching with Memcached or Redis to cut database query times.

Trim the autoloaded options. WordPress reads every autoloaded option on every page load. Plugins that were removed can leave theirs behind. Site Health reports a problem when they add up to 800,000 bytes or more. Look under Tools, then Site Health, then Status. Removing options safely is covered in the WordPress database cleanup guide in this series.

Cut what runs on every request. Each plugin and theme feature adds code and queries to every page. Lighthouse's advice for WordPress is to look for a more optimized theme, to choose an optimization plugin carefully and to upgrade the server. Test on a copy of the site: turn a plugin off, measure again, and keep it off if nothing breaks.

Fix the slow queries. If one page does something expensive in the database, such as an unindexed search or a large report, no cache layer will hide it for long. Use a query profiler to list the slowest queries on a slow page. Lighthouse's advice is to optimize how the server queries the database, or to move to a faster database system.

Fix 3: stop waiting on other services

A page that calls another service while it is being built is as slow as that service. Typical cases are a social feed, a price or stock lookup, a license check, an advertising call and a shipping calculator.

WordPress gives each outside request 5 seconds by default. If a plugin calls a service that is down, every page that needs it can wait 5 seconds before it gives up. That matches the pattern in the table, a delay of nearly the same size every time.

The cure is to take the call off the path of the page:

Fix 4: give the server enough room

If the numbers jump around, the server may be short of memory, processor time or workers.

A PHP server runs a fixed number of workers, and each worker handles one request at a time. In PHP-FPM that limit is the setting pm.max_children. Its comment in the PHP source says it sets the limit on the number of simultaneous requests that will be served, and that the sample default of 5 suits a server without much resources. When every worker is busy, the next request waits in line, and that wait counts as server response time. Slow requests make it worse, because each one holds a worker for longer.

So the order of work is: first make requests shorter with the fixes above, then add workers if the memory allows, then move to a bigger plan. Lighthouse lists more memory or processor time as one of the ways to cut server response time. The hosting guide explains what to compare when you do. Background work such as backups, imports and scheduled tasks should not run in the busiest hours.

Fix 5: shorten the distance and skip the extras

Where to look first on each platform

PlatformFirst places to look
WordPressPage cache, persistent object cache, plugins and theme, autoloaded options, PHP version and OPcache, hosting plan
DrupalThe theme and modules, PHP opcode caching, a memory cache such as Memcached or Redis
MagentoA Varnish integration, which is Lighthouse's own suggestion
Server-rendered ReactStreaming the rendered HTML instead of waiting for the whole page
Static sitesUsually fast already; add a CDN for distance

Check that the fix worked

  1. Run the same measurement again, at least five times, and compare the median.
  2. Test both paths: a request that is answered from the cache, and one that is not, such as the first request after you clear it. The slow path is what a new visitor and a search engine crawler may meet.
  3. Make an edit and check that it appears. A cache that serves old pages is worse than a slow server.
  4. Look at the real-visitor first-byte time in a month's time. Field data covers a rolling 28 days, so it moves slowly. See lab data and field data.

Mistakes to avoid

Check your own page

Run the free audit and look at Document request latency. If the server response line fails, run the measurement above from a terminal and match the pattern to the table. If it passes, the first byte is not your main problem, and the audit's other items will give a bigger gain.

Sources

Start here

Free website audit

Live Google data for any public page: mobile and desktop.

Mobile + desktop · Lighthouse lab test · Real-user Chrome data when Google has it

Rather have this done for you? Speed optimization · Book a call

Related guides

All guides →