Time to First Byte (TTFB)

Measures the time between the request and the first byte of the response.

Check Your Site's Time to First Byte

Enter your website URL on the homepage to see your real TTFB performance data.

What is TTFB?

Time to First Byte (TTFB) measures the time between the browser requesting a page and receiving the first byte of information from the server. It's a fundamental metric that affects all other loading metrics.

TTFB Thresholds

≤ 800ms

Good

≤ 1.8s

Needs Improvement

> 1.8s

Poor

Quick Wins for TTFB

  1. Enable a CDN (Cloudflare free tier is a great start)
  2. Add caching headers to static assets
  3. Use static generation for content that doesn't change frequently
  4. Enable HTTP/2 on your server
  5. Audit and eliminate unnecessary redirects

What TTFB Includes

TTFB is the sum of several network phases:

Redirect
HTTP redirects (if any)
DNS
Domain name resolution
TCP
Connection establishment
TLS
SSL/TLS negotiation
Request
Server processing time

Common Causes of Poor TTFB

1. Slow Server Processing

Complex server-side rendering, slow database queries, or inefficient application code can delay the response.

2. No Caching

Without caching, every request requires the server to generate a fresh response, which is much slower than serving cached content.

3. Geographic Distance

Users far from your server experience higher latency due to the physical distance data must travel.

4. Network Congestion

Overloaded servers, insufficient bandwidth, or network issues between client and server slow down response times.

5. Multiple Redirects

Each redirect adds a full round trip, significantly increasing TTFB. Common culprits: HTTP→HTTPS, www→non-www, trailing slash redirects.

How to Improve TTFB

1. Use a CDN

  • Serve content from edge servers closest to users
  • Popular CDNs: Cloudflare, Fastly, AWS CloudFront, Vercel Edge
  • Cache static assets and HTML at the edge
  • Use edge functions for dynamic content

Example: Vercel Edge Config

// next.config.js
module.exports = {
  // Enable Edge runtime for API routes
  experimental: {
    runtime: 'edge',
  },
}

// Or per-route
export const runtime = 'edge';

2. Implement Caching

  • Use browser caching with proper Cache-Control headers
  • Implement server-side caching (Redis, Memcached)
  • Cache database query results
  • Use stale-while-revalidate patterns

Example: Cache-Control headers

// Static assets (1 year)
Cache-Control: public, max-age=31536000, immutable

// HTML pages (revalidate)
Cache-Control: public, max-age=0, s-maxage=3600, stale-while-revalidate=86400

// API responses
Cache-Control: private, max-age=60

3. Optimize Server Performance

  • Use connection pooling for databases
  • Optimize database queries (indexes, query plans)
  • Enable HTTP/2 or HTTP/3
  • Use efficient server frameworks
  • Scale horizontally with load balancing

Example: Prisma connection pooling

// Use connection pooling in serverless
const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL + '?connection_limit=5&pool_timeout=10'
    }
  }
})

4. Use Static Generation

  • Pre-render pages at build time (SSG)
  • Use Incremental Static Regeneration (ISR)
  • Static pages have near-zero server processing time
  • Perfect for marketing pages, blog posts, documentation

Example: Next.js ISR

// app/blog/[slug]/page.tsx
export const revalidate = 3600; // Revalidate every hour

export async function generateStaticParams() {
  const posts = await getPosts();
  return posts.map(post => ({ slug: post.slug }));
}

5. Eliminate Redirects

  • Link directly to final URLs (include https://, trailing slashes)
  • Use HSTS preload to skip HTTP→HTTPS redirect
  • Consolidate redirect chains into single redirects

Example: HSTS Header

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Measuring TTFB

Using the web-vitals library

import { onTTFB } from 'web-vitals';

onTTFB((metric) => {
  console.log('TTFB:', metric.value);

  // Send to analytics
  analytics.track('TTFB', {
    value: metric.value,
    rating: metric.rating,
    navigationType: metric.navigationType,
  });
});

// You can also use the Navigation Timing API
const [navigation] = performance.getEntriesByType('navigation');
console.log('TTFB:', navigation.responseStart - navigation.requestStart);