Time to First Byte

Metric

The gap between the browser sending a request and the first byte of the response arriving, covering everything before rendering starts.

Why it exists

When a report came in that a page was slow, the places to touch were settled. Shrink the images, split the code, swap in a lighter font. Those are the things on screen, so the cause seems likely to be there too.

Often the numbers didn't move. Take the hero image from one megabyte to 300 kilobytes and the page goes from three seconds to 2.9. The stretch spent downloading the image did shrink; the 2.2 seconds the browser spent waiting with nothing to do, before that, stayed exactly where it was. Nothing about the image work was wrong; it was aimed at the wrong third of the timeline.

The problem was that nothing measured those 2.2 seconds. Metrics for what had been painted on screen already existed, and the stretch before them wasn't collected into a single figure. So the frontend kept getting reworked while the cause stayed in the server and the network. Time to first byte (TTFB) carves that stretch out as one value, which makes the first question answerable: is this a rendering problem or a problem before rendering.

How to calculate it

It's the difference between when the request went out and when the response's first byte arrived. One number, with four stretches inside it, and reducing it starts with seeing which stretch is large.

  1. Name lookup. Turning a domain name into a real server address, usually 20 to 120 milliseconds. It only happens for first-time visitors.
  2. Connection setup. Opening the connection and negotiating encryption, which takes round trips, which means physical distance converts directly into time. A distant server puts this stretch alone past 200 milliseconds.
  3. Server processing. From receiving the request to producing the response, and on a slow page this is more than half of the total. Database queries are usually the cause, and the N+1 problem, where a query repeats once per item in a list, gets caught here often. It's also the only stretch where reading the code tells you much.
  4. Sending the first byte. The time for the first piece of a finished response to reach the browser.

There are two ways to measure. One collects values from real users' browsers; the other runs a tool under fixed conditions. The first mixes regions and connections and therefore shows reality; the second holds conditions constant and is better for comparing changes. Both are needed, and when reading the values use the median and the 75th percentile rather than the mean, which gets dragged around by a very slow minority. A change that improves the median and worsens the 75th percentile is not an improvement.

What a good number looks like

Under 800 milliseconds is good; past 1.8 seconds it needs attention. The line comes from what the number represents: time the user spends waiting in front of nothing. Past a second, people start suspecting the page has stalled.

Splitting it by stretch makes the target concrete. Keep lookup and connection under 200 milliseconds together and server processing under 400, and the total lands below 800. Seeing which stretch crosses its line names the thing to fix.

Region has to be read alongside it. With servers in one region only, a user on the other side of the world spends 300 milliseconds on round trips alone. No code change reduces that; it takes a CDN in front, serving assets from a nearby point of presence, or servers added per region. Judging by domestic numbers hides the 2.4 seconds overseas customers are living with. Pulling the number by region takes one filter and changes what gets worked on.

Cache hits and misses have to be separated too. Storing a result and reusing it is caching, and a cache hit finishes server processing in ten milliseconds. Blend the two cases and the median comes out at a tidy 300 milliseconds while users who miss the cache wait 1.6 seconds. Reporting the miss case is the honest version.

One more thing to hold: this value is the floor for everything after it. With TTFB at 1.2 seconds, the moment the largest piece of content gets painted can never come before 1.2 seconds, no matter how much rendering work gets optimized.

How it sounds at work

"Shrinking the images changes nothing. TTFB is 2.2 seconds."

The cause sits in the stretch before rendering.

"Server processing alone is 1.4 seconds. Let's look at the queries first."

Identifying which of the four stretches is large.

"It's 300 milliseconds domestically and 2.4 seconds overseas."

Regions can't be read blended together.

Theo took this from 1.9 seconds to 600 milliseconds on the Pagedeck document screen over two months. Splitting it up first showed server processing at 1.5 seconds, caused by a query fetching the author separately for every document while rendering the list.

Collapsing that into one query brought processing to 400 milliseconds, and pulling the overseas numbers separately after that still showed 2.1 seconds. Putting a CDN in front, so static assets and some responses came from a nearby point of presence, brought it to 1.1. The two pieces of work were different in kind, and without splitting the stretches there was no way to order them. Both numbers came off the same dashboard and needed different people to fix.

What people get wrong

The most common belief is that reducing this makes the page fast. Reduce the front stretch and the total falls, which is true as arithmetic. But this lowers the floor, and a lowered floor with a thick stack on top of it still means a late page. Cases exist where TTFB went from 1.9 seconds to 400 milliseconds and the first screen still appears at three seconds, with the remaining 2.6 living in images, fonts, and script execution. The two stretches get measured separately and fixed separately. Lowering a floor is worth doing and it is not the same as finishing.

The other frequent reading is that it points at the server. The name mentions the response and server processing genuinely is the largest stretch much of the time, so it sounds right. But only one of the four stretches belongs to the server. A slow name lookup is a domain configuration problem and a slow connection setup is a distance and network problem, and neither shrinks by editing server code. Teams that skip the split and start with the server find out the cause was elsewhere only after optimizing every query and watching the number sit at 1.4 seconds.

Easily confused with

TermWhat moment it ends atHow it differs from TTFB
LCPWhen the largest block on screen finishes paintingIt measures up to the moment a user feels the page arrived. TTFB sits inside it, so this value can never be smaller than TTFB

Where to go next

  • Web performance

    see how metrics, techniques, and problems connect

  • LCP

    the metric covering the stretch right after this one

Last updated 2026-09-16