Hosting owns one number on a web performance report: time to first byte. It is the wait between the browser asking for a page and the first byte of the answer arriving, and it is made of DNS, connection setup, the distance between the visitor and the machine, and the time your server spends thinking. Everything after that first byte - how big your images are, how much JavaScript runs, whether the layout jumps - is your site's problem, and no plan you buy will change it.
That sounds like a small share, and it is not. TTFB is the floor under Largest Contentful Paint: if the server takes 1.5 seconds to answer, a perfect front-end still fails the 2.5-second threshold. Get TTFB under control and the rest becomes solvable. Ignore it and nothing else you do is enough.
The three Core Web Vitals, and where TTFB sits#
Core Web Vitals is a set of three field metrics, measured on real visits and reported at the 75th percentile over a rolling 28 days. The thresholds:
| Metric | What it measures | Good | Poor |
|---|---|---|---|
| LCP | Time until the largest element renders | 2.5s or less | over 4.0s |
| INP | Responsiveness to taps, clicks and keys | 200ms or less | over 500ms |
| CLS | How much the layout shifts while loading | 0.1 or less | over 0.25 |
INP replaced First Input Delay as a Core Web Vital in March 2024, and it is stricter: it looks at the worst interaction on the page rather than only the first, and it measures until the next frame is painted rather than only until the handler starts.
TTFB is not one of the three. It is a diagnostic metric, and the guidance is 0.8 seconds or less for a good rating, with anything past 1.8 seconds treated as poor. It matters because LCP decomposes into four parts that happen in order: TTFB, the delay before the browser discovers the LCP resource, the time to load that resource, and the delay before it renders. The first of those is entirely server-side, and it is a straight subtraction from the budget for the other three.
The 75th percentile is the part people miss. Your own fast connection on a warm cache is irrelevant. One visitor in four has a worse experience than the number you are being scored on, and the tail is made of mobile connections, cold caches and slow devices.
What the first byte is waiting for#
Measure each piece rather than guessing. curl prints the whole breakdown:
$ curl -s -o /dev/null -w "dns: %{time_namelookup}s connect: %{time_connect}s \tls: %{time_appconnect}s ttfb: %{time_starttransfer}s total: %{time_total}s\n" \ https://example.com/Those are cumulative times from the start of the request, so the cost of each stage is the difference from the one before. A typical healthy result from a machine on the same continent looks like DNS under 30 ms, connect adding 20 to 40 ms, TLS adding another 20 to 40 ms, and the first byte arriving 30 to 150 ms after that depending on what the server had to do.
Two things distort this measurement. Run it twice: the second run reuses the DNS answer and gives you a truer picture of a returning visitor. And run it from somewhere that is not your office, because your own latency to the server is not your visitors'.
For the server-side portion, Server-Timing is the tool that turns a guess into a number. Your application emits it and browser devtools display it:
Server-Timing: db;dur=53, render;dur=31, cache;desc="MISS"Add it around your database calls and your template render, deploy it, and the argument about whether the database or the framework is slow ends the same afternoon.
What hosting actually changes#
Four things, in order of how much they typically matter.
Server work. The time between your server receiving the request and starting the reply. For a PHP site this is PHP startup, framework boot, database queries and template rendering. It is where a fast plan is genuinely faster: more CPU share means less queueing, and more memory means the caches stay warm. It is also where the biggest wins are free - OPcache, an object cache, and fixing the page that runs 400 queries.
Distance. Light in fibre covers roughly 200 km per millisecond, and every request needs several round trips before the first byte. From a server in Germany, approximate round-trip times look like this:
| From Germany to | Approximate RTT |
|---|---|
| Western Europe | 10-30 ms |
| Eastern Europe, Turkey | 30-70 ms |
| US East coast | 85-110 ms |
| US West coast, India | 130-180 ms |
| Brazil | 180-220 ms |
| Australia | 250-300 ms |
Multiply by the two or three round trips a fresh HTTPS connection needs and you can see why an Australian visitor starts a second behind before your code runs. No plan fixes that; only a cache nearer the visitor does. Choosing where your server lives is the honest version of that trade-off.
Connection setup. HTTP/2 lets many requests share one connection, so the handshake is paid once rather than per asset. TLS 1.3 completes in one round trip where 1.2 needed two. Keep-alive matters for the same reason. These are mostly your web server's defaults, and they are usually already right.
Disk and memory. NVMe storage shortens everything that touches the filesystem: a cold PHP file read, a database page that is not in memory, a large upload. It shows up most in a database that does not fit in RAM. What NVMe actually changes puts numbers on it.
On RE:NODE all of that sits on NVMe on a ZFS pool in Germany, and the CPU share on your plan is a hard throttle rather than a burst allowance. A hard limit is less flattering on a benchmark and much more predictable in production: a server sitting at 100% is slow, never suspended, and the console graphs memory, CPU and disk against the limits so you can see which one you are actually hitting. Shared CPU and noisy neighbours explains why the throttle is the honest model.
What hosting cannot change#
Be equally clear about this, because it is where most performance money is wasted.
- Image weight. A 3 MB hero image is 3 MB from any server. The LCP element on most pages is an image, and the fix is exporting it at the displayed size in WebP or AVIF.
- JavaScript execution. INP is decided on the visitor's device by your main thread. A faster server cannot make a 400 ms task shorter.
- Layout shift. CLS is caused by images without dimensions, ads and embeds that insert themselves, and fonts that swap to a different size. Pure front-end, every time.
- Third-party tags. Analytics, chat widgets, consent managers and pixels load from other people's servers on other people's schedules.
- Render-blocking resources. A stylesheet in the head blocks rendering until it arrives, whoever is hosting it.
- The visitor's device and network. A five-year-old phone on a train is the 75th percentile.
The practical test before upgrading a plan: look at the CPU and memory graphs during your busiest hour. If you are at 20% CPU and half your memory, a bigger plan will change nothing, and the time to first byte you are unhappy with is coming from your code, your queries or the distance. When to upgrade your plan is the same argument at greater length.
Measuring properly: field against lab#
Two kinds of data, and they answer different questions.
Field data comes from real visits. Chrome's public dataset backs the Core Web Vitals report in Search Console and the top half of PageSpeed Insights, aggregated over 28 days at the 75th percentile. It is the thing search actually uses, it covers your real audience and devices, and it is slow to move - a fix today shows up over the following weeks.
Lab data comes from a synthetic run: Lighthouse, PageSpeed Insights' lower half, WebPageTest. It is repeatable and immediate, which makes it right for comparing two versions of a page, and it cannot measure INP properly because nobody is interacting. A lab run also uses a simulated connection, so its LCP is not your visitors' LCP.
For a site with too little traffic to have field data, collect your own with the web-vitals library, which reports the same metrics from real sessions to any endpoint you like. A hundred real visits tells you more than a thousand lab runs.
When you are chasing a server-side problem specifically, the fastest loop is curl from outside, in a loop, at a quiet hour and at a busy one. A TTFB that is fine at 3 am and terrible at 9 pm is a capacity problem. One that is constantly bad is a code or query problem. One that is bad only for certain pages is a missing index or a slow third-party call in the request path.
Fixing TTFB, in order#
- Cache the HTML. A page served from cache skips the framework, the database and most of the risk. A full-page cache takes a 600 ms dynamic response to 20 ms. For WordPress that is a page cache plugin plus an object cache; for a framework it is a response cache or a reverse proxy. HTTP caching headers explained covers what to send with it so browsers and CDNs cooperate.
- Switch on OPcache and leave it alone. PHP without OPcache recompiles every file on every request. With
opcache.enable=1and enoughopcache.memory_consumption, that work happens once. In production,opcache.validate_timestamps=0removes the stat call per file, at the price of needing a reset on deploy. php.ini settings that matter has the rest. - Count your queries. The commonest cause of a 900 ms TTFB is a loop issuing one query per row. Log the query count per page in development; anything above about 30 on a normal page deserves an explanation.
- Kill the blocking third-party call. A request to an external API inside page rendering makes your TTFB depend on somebody else's uptime. Move it to a queue, cache the result, or accept the risk consciously.
- Remove redirect chains. Each hop is a full round trip, and a redirect to a different hostname adds DNS and TLS again.
http://example.comtohttps://example.comtohttps://www.example.comis two avoidable waits on every first visit. - Compress and keep connections warm. gzip or brotli for text, HTTP/2 on, keep-alive on. These are usually defaults, but check rather than assume.
- Only then, buy more server. If CPU is pegged during traffic or memory is at the limit, the plan is the problem and everything above is rearranging furniture. Sizing a web app for launch day covers how to work out what you need before the day itself.
Fixing LCP once TTFB is good#
With a fast first byte, LCP is decided by how quickly the browser finds and draws the largest element - almost always an image or a big block of text.
- Do not lazy-load the LCP image.
loading="lazy"on the hero delays the very thing being measured. Lazy-load what is below the fold only. - Give it priority.
fetchpriority="high"on the LCP image tells the browser to fetch it before other images, and apreloadlink helps when the image is discovered late, for instance from CSS. - Preconnect to origins you cannot avoid.
rel="preconnect"to a font or image host pays the DNS and TLS cost in parallel instead of in series. - Serve fonts from your own origin with `font-display: swap`. Text that is invisible while a font loads is text that has not rendered.
- Set `width` and `height` on every image. This is the single biggest CLS fix and it costs nothing.
- Cut render-blocking CSS. Inline what the first screen needs and load the rest asynchronously, if your setup allows it without a rewrite.
A static site gets most of this for free, which is part of the argument for building one where the content allows - see static site hosting. A CMS gets it from a caching layer plus discipline about plugins; WordPress speed and caching is the specific version.
FAQ#
What is a good TTFB?
Under 800 ms at the 75th percentile is the published threshold for a good rating, but that is a ceiling rather than a target. A cached page on a nearby server answers in 30 to 80 ms; a dynamic page doing real work should still land under 300 ms. If you are over a second, something is wrong rather than merely unoptimised.
Will a more expensive plan improve my Core Web Vitals?
Only if you are resource-constrained. More CPU and memory shorten the server-work portion of TTFB, which helps LCP. They do nothing for INP, CLS, image weight or third-party scripts, which is where most failing scores come from. Check your usage graphs before you spend.
Does a CDN fix TTFB?
For cached responses, yes, dramatically, because the answer comes from a machine near the visitor. For anything the CDN cannot cache - a logged-in page, a checkout, an API call - the request still travels to your origin and back, so the origin's speed and its distance still decide the number.
Is TTFB a ranking factor?
Not directly. LCP, INP and CLS feed into page experience signals, and TTFB feeds into LCP. Treat it as a means rather than an end: the reason to fix it is that visitors leave slow pages, and that effect is larger than any ranking adjustment.
Why is my Lighthouse score 100 and my Search Console report failing?
Because they measure different things. Lighthouse is one synthetic run on a simulated connection from a datacentre. Search Console reports what real visitors on real devices and networks experienced over the last 28 days, at the 75th percentile. Trust the field data and use the lab run for comparing changes.
How long after a fix does the report improve?
The field data is a rolling 28-day window, so a change takes days to show movement and about a month to be fully reflected. Verify with lab tools and your own real-user measurements immediately; treat the official report as confirmation, not as feedback.




Comments
Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.