How Do You Find Out Why a Page Is Slow on the Server?
How Do You Find Out Why a Page Is Slow on the Server?
Make the server tell you. The Server-Timing response header lets your backend report how long each of its own steps took, and the browser shows those numbers right next to the network request. No log correlation, no guessing, no adding a tracing vendor just to answer one question.
Most performance work stalls at the same wall. You can see that the first byte took 900 milliseconds. You cannot see whether that was the database, a cache miss, a slow template, or a third-party call. The waterfall ends where your code begins.
Server-Timing is the oldest fix for this and still the most underused. It has been in browsers for years, it costs almost nothing, and we add it to nearly every build we work on.
What Is the Server-Timing Header?
It is an HTTP response header for sending backend performance metrics to the browser. MDN describes it as a way to communicate things like database reads and writes, CPU time, and file system access, so they can appear in developer tools and be read through the PerformanceServerTiming interface.
The important word is response. This is not instrumentation you add to your front end. Your server attaches the header to the response it was already sending, and every client that receives that response gets the timings for free.
That makes it uniquely cheap. There is no extra request, no script to load, and no sampling to configure. If the page loaded, the measurement arrived with it.
What Does the Syntax Actually Look Like?
Each metric is a name, optionally followed by a duration and a description, and you separate multiple metrics with commas. The name is required and is a short token such as cpu, db, or cache. The duration parameter is dur, in milliseconds. The description parameter is desc, as a token or a quoted string.
MDN gives several examples that show the range. A bare name with nothing else, such as a metric called missedCache, is valid on its own and works as a flag. A metric such as cpu with dur set to 2.4 reports time. A cache metric can carry both a desc of Cache Read and a dur of 23.2.
Multiple metrics on one line is the normal case. A response might report db with dur 53 and app with dur 47.2 together, and the browser will show both. That comma-separated list is where the diagnostic value lives, because it splits one opaque number into parts you can act on.
How Do You Read Server-Timing in JavaScript?
Through the Performance API, on the resource entries. Call performance.getEntriesByType with the value resource, then read the serverTiming array on each entry. Every item in that array exposes three properties that map straight onto the header: name, duration, and description.
This is what turns the header from a debugging convenience into real monitoring. You can collect those values from actual visitors and send them to your analytics, which means you get backend timings from real devices and real networks rather than from a test run on your own laptop.
That distinction matters more than most teams expect, and we wrote about it separately in our piece on field data against lab data. Server-Timing is one of the few ways to get server-side numbers into the field bucket.
Which Metrics Are Actually Worth Emitting?
Start with four and resist adding more. Total time spent in the database. Time spent waiting on external APIs. Time spent rendering or serialising the response. And whether the response came from cache, which is often just a flag with no duration attached.
Those four answer the question you actually have, which is whether the slowness is yours, someone else's, or a cache that is not working. Adding twenty fine-grained metrics feels thorough and makes the header unreadable at a glance, which defeats the point.
Name them consistently across services. If one service calls it db and another calls it database and a third calls it sql, you cannot aggregate them later, and you will not go back and fix it.
How Does This Connect to TTFB?
Server-Timing explains TTFB. Google's web.dev documentation defines Time to First Byte as the time between starting to navigate to a page and the first byte of the response beginning to arrive. Server-Timing tells you what your server was doing during that window.
It is worth knowing what else lives inside TTFB, because not all of it is your application code. Web.dev lists five components: redirect time, service worker startup time where applicable, DNS lookup, connection and TLS negotiation, and the request time until the first response byte arrives. Only the last one is where your handler runs.
The threshold web.dev gives is 800 milliseconds or less at the 75th percentile, with poor values above 1.8 seconds. If you are over that and your Server-Timing metrics add up to 120 milliseconds, the problem is the network path or a redirect chain, not your code. Our guide to time to first byte covers those cases.
Is TTFB a Core Web Vitals Metric?
No, and web.dev is clear about it. The documentation states that because TTFB is not a Core Web Vitals metric, it is not absolutely necessary for sites to meet the good threshold, provided it does not impede their ability to score well on the metrics that do matter.
That nuance is worth holding onto, because it stops teams optimising the wrong thing. TTFB matters as an input. A slow first byte pushes everything downstream, which is how it ends up hurting Largest Contentful Paint, and LCP is a Core Web Vital.
So treat TTFB as a diagnostic rather than a target. If your LCP is good and your TTFB is 900 milliseconds, you have a number to keep an eye on, not an emergency. Our piece on largest contentful paint explains where that budget actually gets spent.
Is It Safe to Expose Server Timings Publicly?
Not always, and MDN warns about this directly. It notes that Server-Timing may expose sensitive information about your infrastructure, and advises deciding which metrics to send, when to send them, and who should see them based on the use case.
The suggestion MDN makes is a good default: show metrics to authenticated users and nothing on public responses. In practice we often go further and gate detailed timings behind an internal header or a specific cookie, so the data is there when an engineer needs it and absent for everyone else.
There is a cross-origin rule to know as well. Server-Timing is restricted to same-origin by default, and you need the Timing-Allow-Origin header to expose it to another domain. That matters if your assets or APIs sit on a different host from your pages.
Can You Use This on a Site You Did Not Build?
Sometimes, and it is worth checking first. Several hosting platforms and CDNs already emit Server-Timing metrics of their own, describing cache status and edge handling. Open DevTools, look at the response headers for your document request, and see whether anything is there before you write code.
If your platform emits nothing and you cannot change the server, you are back to the usual tools. But on most modern stacks, adding the header is a small middleware that wraps the request, records a few durations, and appends them on the way out. It is an afternoon of work, not a project.
The common blocker is not technical. It is that performance work sits between the front end team and the platform team, and this header needs the platform side to act while the front end side feels the pain.
What Would We Add to a Site This Week?
One middleware, four metrics, and a rule about who sees them. Emit database time, external API time, render time, and a cache hit flag. Gate the detail so public responses carry nothing sensitive. Then look at one slow page and see whether the numbers add up to the first byte.
If they do not add up, that gap is the finding. It usually means a redirect, a DNS or TLS cost, or a cold start somewhere upstream, and none of those get fixed by making your query faster. Knowing which half of the problem you have is most of the work.
If you want a hand instrumenting this, or a page you cannot explain, we are happy to dig in with you. This is standard work for us at phoenix.studio, and the first useful answer usually arrives the same day the header goes live.
Want a site that performs like this?
Tell us about your project. We will come back with a clear next step, no pressure.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Have a project like this?
Tell us where you want to go. We'll tell you how we'd get you there.