What is the Time To First Byte (TTFB) and how to improve it

What is the time to first byte and

Arjen Karel Core Web Vitals Consultant
Arjen Karel
linkedin

What is the Time to First Byte

The time-to-first byte (TTFB) indicates how much time has elapsed in milliseconds between the start of the request and receiving the first response (byte) from a webpage. The TTFB is therefore also referred to as the waiting time. The TTFB is a way to measure the speed of a webpage. The TTFB is a foundational metric, this means that time added to the TTFB will also be added to the Largest Contentful Paint and the First Contentful Paint.

ttfb breakdown

The Time To First Byte can be broken down into 5 pieces:

  1. Redirect time
  2. Worker & Cache time
  3. DNS lookup time
  4. TCP connect time
  5. SSL handshake
  6. Server response

Why is Time to First Byte important

The Time to First Byte is not a Core Web Vital and it is very possible to pass the Core Web Vitals while failing the TTFB metric. That does not mean that the TTFB is not important. The TTFB is an extremely important metric to optimize and fixing the TTFB will greatly improve pagespeed & the page experience!

The impact of TTFB for visitors

The time to first byte preceded all other paint metrics. While the browser is waiting for the Time to First byte it the browser cannot do anything an d will just show a blank screen! This means that any increase in time to first byte will result in extra 'blank screen' time and any decrease in the time to first byte will translate into less 'blank screen' time.

To get that 'feeling of instant loading pages' the time to first byte needs to be as fast as possible!

How to Measure the Time To First Byte TTFB

PageSpeed TIP: every resource has it's own time to first byte. In this context however we are talking about the time to first byte of the main page!

The Time to First Byte can greatly fluctuate between different user with different devices and from different locations. That is why self-measuring the time to first byte from your desktop computer is probably not a great idea. Using tools like pingdom or GTMetrix is not reliable for the same reason.

The best way to measure the Time To First Byte is to collect Real User Metrics (RUM) data from your visitors. You can do this yourself with this code or use a RUM tool like CoreDash

const formatTime = (time) => {
  //round by 2 decimals, use Math.round() for integer
  return Math.round(time * 100) / 100;
};

new PerformanceObserver((entryList) => {
  const [pageNav] = entryList.getEntriesByType('navigation');

  // timing start times are relative
  const activationStart = pageNav.activationStart || 0;
  const workerStart = Math.max(pageNav.workerStart - activationStart, activationStart);
  const dnsStart = Math.max(pageNav.domainLookupStart - activationStart, workerStart);
  const tcpStart = Math.max(pageNav.connectStart - activationStart, dnsStart);
  const sslStart = Math.max(pageNav.secureConnectionStart - activationStart, tcpStart);
  const requestStart = Math.max(pageNav.requestStart - activationStart, sslStart);
  const responseStart = Math.max(pageNav.responseStart - activationStart, requestStart);

  // attribution based on https://www.w3.org/TR/navigation-timing-2/#processing-model
  // use assosictive array to log the results more readable
  let attributionArray = [];
  attributionArray['Redirect Time'] = { 'time in ms': formatTime(workerStart - activationStart) };
  attributionArray['Worker and Cache Time'] = { 'time in ms': formatTime(dnsStart - workerStart) };
  attributionArray['DNS Time'] = { 'time in ms': formatTime(tcpStart - dnsStart) };
  attributionArray['TCP Time'] = { 'time in ms': formatTime(sslStart - tcpStart) };
  attributionArray['SSL Time'] = { 'time in ms': formatTime(requestStart - sslStart) };
  attributionArray['Request Time'] = { 'time in ms': formatTime(responseStart - requestStart) };
  attributionArray['Total TTFB'] = { 'time in ms': formatTime(responseStart - activationStart) };

  // log the results
  console.log('%cTime to First Byte (' + formatTime(responseStart - activationStart) + 'ms)', 'color: blue; font-weight: bold;');
  console.table(attributionArray);

  console.log('%cOrigininal navigation entry', 'color: blue; font-weight: bold;');
  console.log(pageNav);

}).observe({
  type: 'navigation',
  buffered: true
});

What is a good TTFB score?

time to first byte

ttfb breakdown coredash

It's recommended that your server responds to navigation requests quickly enough so that the 75th percentile of users experience an FCP within the "good" threshold. As a rough guide, most sites should strive to have a TTFB of 0.8 seconds or less.

How to improve the TTFB - Avoid redirects

When a user requests a web page, the server may respond with a redirect to another page. This redirect can add additional time to the TTFB because the browser must make an additional request to the new page. 

There are several ways to avoid redirects or minimize the impact of redirects: 

  1. Update your internal links! Whenever you change the location of a page update your internal links to that page to ensure no references to the earlier page location remains.
  2. Handle redirects on the server level.
  3. Use relative URLs: When linking to pages on your own website, use relative URLs instead of absolute URLs. This will help prevent unnecessary redirects.
  4. Use canonical URLs: If you have multiple pages with similar content, use a canonical URL to indicate the preferred version of the page. This will help prevent duplicate content and unnecessary redirects. 
  5. Use 301 redirects: If you must use a redirect, use a 301 redirect instead of a 302 redirect. A 301 redirect is a permanent redirect, while a 302 redirect is a temporary redirect. Using a 301 redirect will help prevent unnecessary redirects.

How to improve the TTFB - Speed up the initial connection

A high Time to First Byte can have multiple causes. However DNS, TCP and SSL affect all time to first bytes. So let's start there. Even though optimizing these 3 may not yield the biggest results optimizing these will optimize every single TTFB!

Speed up DNS

PageSpeed TIP: DNS TPC & SSL are usually a bigger issue when you are using a cheap host or when you serve to a global audience while not using a CDN. Use RUM tracking to view your Global TTFB and break down toe TTFB into it's sub-parts

Use a Fast DNS Provider. Not all DNS providers are as fast as others. Some (free) DNS providers are just slower then other (free) DNS providers. CloudFlare for example will give you one of the worlds fastest DNS providers for free!

Increase the DNS TTL. Another way is to increase the Time to Live (TTL) value . TTL is a setting that determines how long the lookup can be cached. The higher the TTL, the less likely the browser will need to perform another DNS lookup. It is important to note that ISPs also cache DNS.

Speed up TCP

The 'TCP part' of the TTFB is the initial connection to the webserver. When connecting the browser and the server share information about how information will be exchanged. You can speed up TCP by connecting to a server that is geographically close to your location and by ensuring the server has enough free resources. Sometimes changing to a lightweight server like NGINX can speed up the TCP part of the TTFB. In many cases using a CDN will speed up the TCP connection!

Speed up SSL/TSL

Once the TCP connection has been made the browser and the server will need to secure your connection through encryption. You can speed this up by using faster, newer and more lightweight protocols (SSL Cyphers) and by being geographically closer to your webserver (since the TSL negotiation takes quite a few back and forth round-trips). Using a CDN will often improve the SSL connection time since they are often very well configured and have multiple servers all across the globe. TLS 1.3 in particular is designed to keep TLS negotiation as short as possible.

How to improve the TTFB - Speed up the server side

Page Caching

By far the most efficient way to speed up the time to first byte is to server the HTML from the server cache. There are several ways to implement full page caching. The most effective way is by doing this directly at the web-server level with for example the NGINX caching module or by using Varnish as a reverse caching proxy.

There also are a lot of plugins for difference CMS systems that will cache full pages and many SPA frameworks like NextJS have their own implementation of full page caching along with different invalidation strategies.

If you would like to implement you own caching the basic idea is super simple. When a client requests a page check if it exists in the cache folder. If it does not exist, create the page, write it to cache and show the page like you normally would. On any next request to the page the cache file will exist and you can serve the page directly from cache.

Partial caching

With partial caching the idea is to cache frequently used, slow or expensive parts of the page or resources (like api calls, database results) for fast retrieval. This will eliminate bottlenecks when generating a page. If you are interested in these types of optimizations (you should be interested!!) look up these concepts: Memory Cache, Object Cache, Database Cache, Object-Relational Mapping (ORM) Cache,Content Fragment Cache and Opcode Cache.

Optimize the application code

Sometimes the page cannot be served from (partial) cache because the cache file does not exist, large parts of the pages are dynamic or because you run into other issues. That is why we need to optimize the application code. How this is done depends entirely on your application. Ir is based on re-writing and optimizing slow parts of your code.

Optimize database queries

Most of the time ineffective database queries are the root cause of a slow Time to First Byte. Start by logging 'slow queries' and 'queries not using indexes' to disk. Analyze them, add indexes or ask an expert to perform database tuning to fix these issues. See https://www.mongodb.com/docs/atlas/performance-advisor/ and https://dev.mysql.com/doc/refman/8.0/en/slow-query-log.html

Reduce internal network latency

A bad practice that I come across more times that I would like is a delay in time to first byte caused by slowness causes by communication between the web application and the data storage. This usually only happens with large sites that have outsourced their data storage to cloud API's.

How to improve the TTFB - speed up the client side

Client side caching

Client-side caching involves the user’s browser storing resources that they’ve already accessed, like images and scripts. So when the user comes back to your website, their browser can quickly retrieve the cached resources instead of having to download them again. This can significantly reduce the number of requests made to the server, which in turn can reduce the TTFB.

To implement client-side caching, you can use the HTTP Cache-Control header. This header allows you to specify how long the browser should cache a particular resource.

You could consider completely caching the html of the page on the client side. This will dramatically reduce the TTFB since we do not need a request anymore. The downside is that once the page is in the browsers cache, any updates on the live version of the page will not be seen by the user until the page cache expires.

Service Workers

Service workers are scripts that run in the background of a user’s browser and can intercept network requests made by the browser. This means that service workers can cache resources like html, images, scripts, and stylesheets, so that when the user comes back to your website, their browser can quickly retrieve the cached resources instead of having to download them again.

Speculation Rules API

The Speculation Rules API is designed to improve performance for future navigation. Once a visitor has landed on your page you can use the speculationrules instruct a browser to fetch (with the prefetch directive) or even render (with the prerender directive) pages that the visitor is most likely to visit. The Speculation rules API is more flexible and configurable then the link prefetch method.

Take a look at his example where to browser is instructed to prefetch url in the menu bar for a future navigation, keeping it in memory so that it can be used to speed up the next navigation.
<script type="speculationrules">
{"prerender": 
[{
  "source": "document",
  "where": {"selector_matches": "nav a"},
  "eagerness": "moderate"
}]}
</script>

Page Prefetching

If you do not want to use the Speculation Rules API because of it's poor browser support or you could use a small script called quicklink. This will prefetch all the links in the visible viewport and all but eliminate the Time To First Byte for these links! 

The downside to quicklinks is that it requires more browser resources but for now it will outperform the speculation rules API.

How to improve the TTFB - leverage a CDN

CDN

ttfb by country cdnT
TTFB with a CDN and edge caching
ttfb country no cdnT
TTFB without a CDN hosted in Germany

Avoid redirects


What is the Time To First Byte (TTFB) and how to improve itCore Web Vitals What is the Time To First Byte (TTFB) and how to improve it