Blog

What is a good time to first byte? TTFB benchmarks, what it is made of and why rising TTFB warns of outages

TTFB benchmarks for real sites, how DNS, TCP, TLS and server processing add up, how to measure from several regions and how to alert on rising TTFB before an outage.

A good time to first byte is 0.8 seconds or less as experienced by real users, which is the threshold Google's web.dev guidance uses. Anything above 1.8 seconds counts as poor. For the part your server actually controls, the processing time after the TLS handshake, a practical target is under 200 ms for cached pages and under 500 ms for dynamic ones. The total always depends on where you measure from, because distance adds network round trips before your server starts working.

This guide breaks TTFB into its parts, shows how to measure each one with curl, explains why the same page has different TTFB in different regions and how to use a slowly rising TTFB as a warning sign days before something falls over.

What is a good time to first byte? The benchmarks

There is no single correct number, because people mean different things by TTFB. Three reference points are useful:

  • Field TTFB (real users): web.dev rates 0.8 s or less at the 75th percentile as good, 0.8 to 1.8 s as needing improvement and above 1.8 s as poor. This measurement starts at navigation and includes redirects, DNS, connection setup and server time.
  • Lab server response time: Lighthouse flags the initial document response when the server takes longer than 600 ms to answer.
  • Server processing share: the time between the request being sent on an established connection and the first byte coming back. This is the number you can actually move with code, caching and database work. Under 200 ms for cached or static responses and under 500 ms for dynamic, database-backed pages are sensible working targets.

The first two benchmarks describe user experience. The third describes your backend. When someone asks whether their TTFB is good, the honest answer is usually: check the server share first, because the network share is mostly physics.

What makes up TTFB: DNS, TCP, TLS and server processing

On a fresh connection to an HTTPS site, the first byte can only arrive after several steps have finished in sequence:

  1. DNS lookup. The client resolves the hostname. Cached answers take almost nothing, an uncached lookup through a slow resolver can take tens or hundreds of milliseconds.
  2. TCP handshake. One round trip between client and server.
  3. TLS handshake. One additional round trip with TLS 1.3, two with TLS 1.2. Session resumption can shorten this.
  4. Request and server processing. The request travels to the server, the application routes it, queries databases or caches, renders and starts writing the response.
  5. First byte back. The response travels back, which is another half round trip.

This gives you a network floor you cannot optimise away in code. With a round-trip time of 150 ms between a probe and your origin, TCP plus TLS 1.3 plus the request itself already cost roughly three round trips, about 450 ms, before a single millisecond of server processing. The same server measured from a probe 10 ms away shows a fraction of that.

That is why a TTFB of 600 ms can be excellent from one continent and alarming from another. Comparing raw TTFB numbers across locations without splitting them into phases leads to wrong conclusions.

How to measure TTFB and split it into phases

curl exposes timing variables for each phase. They are cumulative, measured from the start of the request:

curl -o /dev/null -s -w '\ndns:     %{time_namelookup}\nconnect: %{time_connect}\ntls:     %{time_appconnect}\nttfb:    %{time_starttransfer}\ntotal:   %{time_total}\n' https://example.com/

An example output might look like this:

dns:     0.012
connect: 0.041
tls:     0.089
ttfb:    0.312
total:   0.330

Read it as differences, not absolute values:

  • DNS: 12 ms
  • TCP: 41 - 12 = 29 ms (roughly one round trip)
  • TLS: 89 - 41 = 48 ms
  • Server processing plus one round trip: 312 - 89 = 223 ms

Subtract one round trip (about the TCP time) from the last value and you have an estimate of pure server time, here around 190 ms. That is the number to track over time. If you want the breakdown inside the server too, emit a Server-Timing header from your application:

Server-Timing: db;dur=84, render;dur=61, cache;desc="miss"

Browser developer tools display these values next to the request timing, so you can see whether a slow first byte is the database, the template or a cache miss without attaching a profiler.

Two rules make measurements comparable. First, decide whether you measure a cold or warm connection: curl opens a new connection every time, a browser reusing a connection skips DNS, TCP and TLS entirely. Second, know whether the URL is served from a CDN cache. A cached HTML page hides the origin completely, so for backend health measure an uncached endpoint that touches the database, for example a health route. The guide on monitoring API endpoints with health checks and latency thresholds covers how to design such an endpoint.

Measuring TTFB from different regions

A single measurement from your laptop tells you very little. Run the same request repeatedly from several locations and look at percentiles instead of averages, because averages hide the slow tail that users actually notice:

for i in $(seq 1 20); do
  curl -o /dev/null -s -w '%{time_starttransfer}\n' https://example.com/health
done | sort -n | awk '{a[NR]=$1} END {print "p50:", a[int(NR*0.5)], "p95:", a[int(NR*0.95)]}'

Run this from a few machines in different regions, or use monitoring probes that already sit there. Then compare the phases, not the totals:

  • Network phases differ, server phase is equal: normal. Distance costs round trips. Fix with a CDN, edge termination of TLS or a closer origin, not with backend work.
  • Server phase differs by region: different requests are hitting different backends. Typical causes are a cold CDN point of presence, a replica database in one region lagging or a misrouted load balancer.
  • DNS phase is high in one region only: resolver or authoritative nameserver latency for that location, worth checking against your DNS setup.
  • Everything is slow from one region, suddenly: often a routing problem between that network and yours. Before you start debugging, confirm with a network check from probes worldwide whether others see the same.

Regional TTFB data is also a good sanity check for any claim like "the site is fast". It is fast from somewhere. The question is whether it is fast from where your customers are.

Why rising TTFB is an early warning before outages

Most outages are not a switch flipping from fine to broken. Before a service stops answering, it usually answers more slowly: queues fill, connection pools run dry, a database query degrades as a table grows. TTFB is where that shows up first, because the server processing phase stretches long before requests start timing out.

The useful signal is not whether one TTFB value is good, but whether the server share of TTFB is moving away from its own baseline.

Typical patterns and what they tend to mean:

  • Slow creep over days or weeks: data growth hitting a missing index, a cache whose hit rate is falling, a memory leak causing more garbage collection. Easy to miss on a dashboard, obvious when you compare this week's p95 to last month's.
  • Step change after a deploy: a new query, an N+1 pattern or a disabled cache. Correlate TTFB jumps with deploy times.
  • Regular sawtooth: scheduled jobs competing with web traffic, backups locking tables, log rotation. If the spikes line up with cron schedules, move the jobs or give them their own resources.
  • Rising p95 while p50 stays flat: a subset of requests is struggling, often lock contention or one slow dependency. This is frequently the last warning before timeouts and 5xx errors.
  • All regions slow at once: the origin itself. One region slow: network or edge.

A server that went from 150 ms to 900 ms of processing time over a week is still up by every uptime check. It is also one traffic spike away from timeouts.

How to set TTFB alert thresholds

TTFB alerts are early warnings, so they should behave differently from down alerts. A workable setup:

  1. Measure a baseline: p95 TTFB per region over at least one normal week, ideally on an uncached endpoint.
  2. Set a warning threshold relative to that baseline, for example p95 above twice the baseline, sustained for 10 to 15 minutes. Sustained matters: single slow checks are noise.
  3. Add an absolute ceiling based on the benchmarks above, for example server share above 800 ms, so a slowly drifting baseline cannot normalise bad performance.
  4. Require more than one region to agree before treating it as an origin problem. A single slow region gets its own, lower-priority notification.
  5. Route TTFB warnings to a chat channel or ticket queue, not to the pager. Nobody should wake up for 700 ms. Keep paging for confirmed downtime.
  6. Keep the request timeout of your uptime check well above the warning threshold, so slowness and downtime stay two separate signals.

If slow-response alerts start firing for blips, the same techniques as for down checks apply. The article on reducing false positive alerts with retries, realistic timeouts and split thresholds goes through them in detail.

Tracking TTFB as part of uptime monitoring

You can collect all of the above with cron and curl on a few small servers, but you then also own the storage, the percentiles and the alerting. Most uptime monitoring tools already make an HTTP request from several locations on every check, which is the same request that produces a TTFB value.

m0nitor is one option: its HTTP(S) and other monitor types run on a fixed interval from distributed probes in several regions, and an outage is only confirmed when multiple locations agree, which keeps single-route network blips out of your alerts. Definitions for TTFB, SLO, error budget and related terms are collected in the monitoring glossary. Whatever tool you use, the approach stays the same: regional measurements, percentiles, a baseline and a warning threshold that sits below the point where checks fail.

FAQ

Is a TTFB of 200 ms good?

Yes, for most sites 200 ms is a good time to first byte. As a server processing time it is in line with a cached or well-optimised page, and as a total including DNS, TCP and TLS it usually means the client is close to the server or to a CDN edge.

What is the difference between TTFB and response time?

TTFB ends when the first byte of the response arrives. Total response time ends when the last byte arrives, so it additionally includes transferring the full body. For small HTML or JSON responses the two are close, for large downloads the transfer dominates.

Does a CDN improve TTFB?

For cacheable content, yes, because the response comes from a nearby edge and skips the origin entirely. For uncached, dynamic requests a CDN mainly shortens connection setup by terminating TCP and TLS closer to the user, while server processing time at the origin stays the same.

Why is my TTFB higher in some regions than others?

Usually because of distance: each round trip for TCP, TLS and the request takes longer the further the client is from the server. If the server processing share also differs between regions, look at CDN cache state, regional replicas and load balancer routing.

Product

  • Pricing
  • Features
  • Integrations
  • Security
  • Free network check

Features

  • Uptime monitoring
  • Status pages
  • Alert workflows
  • Incident management
  • Dependencies
  • AI assistant
  • Global infrastructure
  • On-call schedules
  • Enterprise SSO

Use cases

  • Websites for free
  • Cron jobs
  • SSL certificates
  • Databases
  • IP blacklists
  • GDPR compliance

Resources

  • What is a status page?
  • Documentation
  • API
  • MCP server
  • Monitoring glossary
  • Free tools
  • SLA calculator
  • SSL checker
  • DNS lookup
  • Blog
  • Changelog
  • About
  • Contact

Compare

  • Free uptime monitoring
  • UptimeRobot
  • Better Stack
  • Pingdom
  • StatusCake
  • Uptime Kuma
  • Hyperping
  • Atlassian Statuspage
  • Instatus
  • Cachet
  • Freshping