Time to First Byte (TTFB): Los het knelpunt op dat alles vertraagt

Je server heeft 2,3 seconden nodig om te reageren. In die tijd zien gebruikers een leeg scherm. Niets laadt. Geen afbeeldingen, geen tekst, helemaal niets. Ze zijn weg voordat je pagina zelfs maar begint te renderen. TTFB is de verborgen rem op alle andere metrics.

Time to First Byte optimalisatie

Wat is TTFB (en waarom het belangrijk is)?

TTFB meet hoe lang het duurt voordat de browser de eerste byte ontvangt van je server. Het is de tijd van het moment dat een gebruiker een pagina opvraagt tot het moment dat de server begint met het verzenden van data. Gedurende deze tijd zien gebruikers een leeg scherm.

Belangrijk: TTFB is geen officieel Core Web Vital, maar heeft direct invloed op LCP en FCP. Google beschouwt het als een fundamentele metric voor algehele paginaprestaties. Als je TTFB traag is, laadt alles te laat.

Let op: TTFB heeft meerdere definities

Verschillende meettools hanteren verschillende beginpunten voor TTFB-berekeningen. Begrijpen welke variant je meet is essentieel voor nauwkeurige prestatieanalyse en eerlijke vergelijkingen.

TTFB-normen (Navigation TTFB)

Good800 ms of minder
Needs Improvement800 ms tot 1800 ms
PoorBoven 1800 ms

In deze gids gebruiken we Navigation TTFB (de CrUX-definitie) tenzij anders aangegeven.

Wat is er inbegrepen in Navigation TTFB?

Navigation TTFB components (startTime → responseStart):

1. Redirects          (0ms if no redirects)
2. Service worker     (0ms if not used)
3. Browser cache      (checking local cache)
4. DNS lookup         (0-100ms, or 0ms if cached)
5. TCP connection     (1 RTT, or 0ms if reused)
6. TLS handshake      (1-2 RTT, or 0ms if reused)
7. HTTP request       (minimal)
8. Server processing  (varies widely)
9. Response start     (first byte arrives)

Note: Many subparts can be 0ms depending on caching,
connection reuse, and other factors.

TTFB-variabiliteit begrijpen

TTFB combineert meerdere onderdelen die zich anders gedragen afhankelijk van caching en verbindingsstatus. Aanvragen op bestaande verbindingen slaan DNS en TLS over (0 ms), terwijl nieuwe verbindingen de volledige overhead hebben. Resources in de cache omzeilen het netwerk volledig. Dit leidt tot duidelijk verschillende prestatieclusters in je data — sommige laadtijden zijn snel, andere traag — waardoor gemiddelde of percentielwaarden belangrijke patronen in de gebruikerservaring kunnen verhullen.

Waarom TTFB belangrijk is voor prestaties

TTFB is het startschot voor het laden van de pagina. Elke milliseconde TTFB-vertraging telt op bij LCP, FCP en de totale laadtijd. Een snelle TTFB versterkt alle andere optimalisaties.

Impact op LCP

Als TTFB 2 seconden is, kan je LCP niet beter zijn dan 2 seconden. Een snelle TTFB geeft je ruimte om andere aspecten van het laden te optimaliseren.

Impact op FCP

Er wordt niets gerenderd totdat de HTML binnenkomt. Een trage TTFB betekent dat gebruikers langer naar een leeg scherm staren, zelfs als je CSS en JavaScript perfect zijn geoptimaliseerd.

Waargenomen prestaties

Gebruikers op trage verbindingen zijn bijzonder gevoelig voor TTFB. Een vermindering van 500 ms in TTFB voelt dramatisch sneller dan het micro-optimaliseren van JavaScript.

TTFB terugbrengen van 1,5 s naar 500 ms kan de conversie met 7–10% verhogen. Serversnelheid is onzichtbaar — maar gebruikers voelen het direct.

TTFB meten

Velddata (echte gebruikers)

Echte TTFB varieert per locatie, netwerkkwaliteit en serverbelasting. Velddata toont wat je gebruikers daadwerkelijk ervaren:

Labdata (testen)

Test TTFB vanuit verschillende locaties en configuraties:

  • WebPageTest — test vanuit meerdere wereldwijde locaties, toont TTFB-uitsplitsing
  • Lighthouse — rapporteert TTFB in de diagnosticssectie
  • Chrome DevTools — het Network-tabblad toont timing voor elke aanvraag

TTFB meten in Chrome DevTools

// Chrome DevTools Network tab:
// 1. Open DevTools (F12)
// 2. Go to Network tab
// 3. Reload the page
// 4. Click on the main document request
// 5. Go to Timing tab
// 6. "Waiting for server response" = TTFB

// TTFB includes:
// - Queueing
// - Stalled
// - DNS Lookup
// - Initial connection
// - SSL
// - Request sent
// - Waiting (TTFB)

TTFB programmatisch meten

Installeer de web-vitals library:

npm install web-vitals

Track vervolgens TTFB:

import {onTTFB} from 'web-vitals';

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

  // Send to analytics
  analytics.track('ttfb', {
    value: metric.value,
    rating: metric.rating, // 'good', 'needs-improvement', 'poor'
    navigationType: metric.navigationType
  });
});

// Or use Navigation Timing API directly
const observer = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  entries.forEach((entry) => {
    if (entry.entryType === 'navigation') {
      const ttfb = entry.responseStart - entry.requestStart;
      console.log('TTFB:', ttfb);
    }
  });
});

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

Veelvoorkomende oorzaken van trage TTFB

1. Trage serververwerking

Server-side rendering, databasequeries en API-aanroepen tellen allemaal op bij TTFB. Complexe paginalogica kan honderden milliseconden in beslag nemen voordat de eerste byte wordt verzonden.

Fix: Cache gerenderde pagina's, optimaliseer databasequeries, gebruik edge rendering.

2. Geen CDN of slechte CDN-configuratie

Gebruikers ver van je oorspronkelijke server hebben een hoge latentie. Een gebruiker in Australië die een aanvraag doet bij een Amerikaanse server voegt 200–300 ms toe alleen al voor de retour­reis.

Fix: Gebruik een wereldwijd CDN om content te serveren vanuit edge-locaties dicht bij gebruikers.

3. Onvoldoende serverresources

Onderbemande servers worstelen onder belasting. CPU-knelpunten, geheugenbeperkingen en trage schijf-I/O verhogen allemaal TTFB tijdens verkeerspieken.

Fix: Schaal serverresources op, implementeer caching, optimaliseer de backend-code.

4. Databasequeryprestaties

Trage queries, ontbrekende indexen en N+1-queryproblemen kunnen seconden toevoegen aan TTFB. Elke niet-gecachede databaseaanvraag voegt latentie toe.

Fix: Voeg database-indexen toe, implementeer querycaching, gebruik leesreplica's.

5. Netwerklatentie

DNS-opzoektijd, TCP-handshake en TLS-onderhandeling dragen allemaal bij aan TTFB. Slechte netwerkrouting kan aanzienlijke overhead toevoegen.

Fix: Gebruik DNS-prefetching, schakel HTTP/3 in, implementeer connection prewarming.

TTFB-optimalisatietechnieken

1. Gebruik een CDN voor edge caching

Stel juiste cache-headers in

// Express.js: Set cache-control headers
app.get('/api/data', (req, res) => {
  res.set('Cache-Control', 'public, max-age=3600, s-maxage=86400');
  res.json(data);
});

// Nginx: Cache static assets
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

Impact: CDN-caching kan TTFB verlagen van 500–1000 ms naar 20–50 ms voor gecachede responses.

2. Serververwerking optimaliseren

Databasequeryoptimalisatie

// Bad: N+1 query problem
const users = await db.query('SELECT * FROM users');
for (const user of users) {
  user.posts = await db.query(
    'SELECT * FROM posts WHERE user_id = ?',
    [user.id]
  );
}
// TTFB: 500-2000ms (100 queries)

// Good: Single query with JOIN
const users = await db.query(`
  SELECT
    users.*,
    posts.id as post_id,
    posts.title as post_title
  FROM users
  LEFT JOIN posts ON posts.user_id = users.id
`);
// TTFB: 50-150ms (1 query)

// Better: Add indexes
CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_users_email ON users(email);
// Query time: 100ms -> 5ms

Incrementele statische regeneratie implementeren

// Next.js: ISR for fast TTFB with fresh content
export async function getStaticProps() {
  const data = await fetchData();

  return {
    props: { data },
    // Serve cached page, rebuild in background
    revalidate: 60 // Check for updates every 60 seconds
  };
}

// First request after revalidate:
// - User gets cached version (TTFB: 50ms)
// - New version builds in background
// - Next user gets updated version

// Without ISR:
// - Every request hits database (TTFB: 500ms+)

3. HTTP/3 en moderne protocollen inschakelen

// Cloudflare: HTTP/3 enabled by default
// Reduces TTFB by 20-30% on mobile networks

// Nginx: Enable HTTP/3
server {
  listen 443 quic reuseport;
  listen 443 ssl http2;

  ssl_protocols TLSv1.3;
  ssl_early_data on; # 0-RTT

  add_header Alt-Svc 'h3=":443"; ma=86400';
}

// Benefits:
// - Faster connection establishment
// - Better mobile performance
// - Head-of-line blocking eliminated
// - 0-RTT resumption (saves 1 RTT on repeat visits)

4. DNS-opzoektijd verminderen

<!-- DNS prefetching for external domains -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="dns-prefetch" href="//analytics.example.com">

<!-- Preconnect for critical origins -->
<link rel="preconnect" href="//api.example.com" crossorigin>

<!-- Use a fast DNS provider -->
Cloudflare DNS: ~10ms lookup time
Google DNS:     ~20ms
Default ISP:    ~50-200ms

<!-- Benefits: -->
DNS Prefetch:  Saves 20-100ms on first request
Preconnect:    Saves 20-100ms + TCP/TLS time

Geavanceerde TTFB-optimalisatiestrategieën

Edge rendering met Cloudflare Workers / Vercel Edge

// Render React at the edge, closest to users
import { renderToString } from 'react-dom/server';
import App from './App';

export default async function handler(request) {
  const html = renderToString(<App />);

  return new Response(html, {
    headers: {
      'Content-Type': 'text/html',
      'Cache-Control': 'public, s-maxage=60'
    }
  });
}

// Benefits:
// - 10-30ms TTFB globally
// - No origin server load
// - Scales infinitely

Geavanceerd: 103 Early Hints

Met 103 Early Hints kunnen servers resource-preload-instructies sturen voordat de volledige HTML-response gegenereerd is. Terwijl de server de aanvraag verwerkt, kan de browser alvast beginnen met het downloaden van kritieke CSS en lettertypen. Dit kan de gemeten TTFB met 200–500 ms verlagen.

Gebruik dit alleen als je trage server-side verwerking hebt en weet welke resources kritiek zijn. Cloudflare en Fastly ondersteunen dit van nature. Lege 103-responses zonder zinvolle resource hints manipuleren slechts de metric zonder de echte prestaties te verbeteren.

Cold starts optimaliseren voor serverless

// Vercel/Netlify: Reduce cold start times

// Bad: Large dependencies
import _ from 'lodash'; // 100KB
import moment from 'moment'; // 200KB
// Cold start: 500-1000ms

// Good: Import only what you need
import debounce from 'lodash/debounce'; // 5KB
import { format } from 'date-fns'; // 10KB
// Cold start: 100-200ms

// Keep functions warm
// - Use Vercel Edge Functions (no cold starts)
// - Or ping functions every 5 minutes
// - Or use reserved concurrency (AWS Lambda)

Database connection pooling

// Reuse database connections
import { Pool } from 'pg';

const pool = new Pool({
  max: 20, // Max connections
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000
});

// Bad: New connection each request (100-200ms overhead)
app.get('/data', async (req, res) => {
  const client = new Client();
  await client.connect();
  const result = await client.query('SELECT * FROM data');
  await client.end();
  res.json(result.rows);
});

// Good: Reuse pooled connections (5-10ms overhead)
app.get('/data', async (req, res) => {
  const result = await pool.query('SELECT * FROM data');
  res.json(result.rows);
});

TTFB monitoren over tijd

TTFB kan langzaam verslechteren naarmate het verkeer groeit of de code complexer wordt. Monitor het proactief.

TTFB tracken per route en locatie

import {onTTFB} from 'web-vitals';

onTTFB((metric) => {
  analytics.track('ttfb', {
    value: metric.value,
    rating: metric.rating,
    page_path: location.pathname,
    navigation_type: metric.navigationType,
    connection_type: navigator.connection?.effectiveType,

    // Server timing breakdown (if available)
    server_timing: getServerTimingMetrics()
  });
});

function getServerTimingMetrics() {
  const navigation = performance.getEntriesByType('navigation')[0];
  const serverTiming = navigation.serverTiming || [];

  return serverTiming.map(entry => ({
    name: entry.name,
    duration: entry.duration
  }));
}

Server-Timing header voor debugging

// Express middleware: Track backend timing
app.use((req, res, next) => {
  const start = Date.now();
  const timings = {};

  res.on('finish', () => {
    const total = Date.now() - start;
    res.set('Server-Timing', [
      `total;dur=${total}`,
      `db;dur=${timings.db || 0}`,
      `cache;dur=${timings.cache || 0}`,
      `render;dur=${timings.render || 0}`
    ].join(', '));
  });

  req.timing = timings;
  next();
});

// In route handler
app.get('/product/:id', async (req, res) => {
  const cacheStart = Date.now();
  const cached = await cache.get(req.params.id);
  req.timing.cache = Date.now() - cacheStart;

  if (cached) return res.json(cached);

  const dbStart = Date.now();
  const product = await db.getProduct(req.params.id);
  req.timing.db = Date.now() - dbStart;

  res.json(product);
});

// Visible in Chrome DevTools Network -> Timing tab

Alerts instellen

  • P75 TTFB-norm: Alert als het 75e percentiel boven 800 ms uitkomt
  • Regionale monitoring: Volg TTFB per geografische regio
  • Regressiedetectie: Alert bij een TTFB-stijging van meer dan 100 ms na een deployment
  • CDN cache hit rate: Alert als de CDN cache hit rate onder een doelnorm zakt

Performance budgets

  • TTFB P75: Onder 800 ms wereldwijd
  • CDN cache hit rate: Boven 90%
  • Databasequerytijd: Onder 50 ms voor de meeste queries
  • Oorspronkelijke serverrespons: Onder 200 ms voor gecachede content

TTFB-optimalisatiechecklist

Hulp nodig bij het verlagen van je TTFB?

Serveroptimalisatie vereist diepgaande infrastructuurkennis. Wij kunnen je backend auditeren, knelpunten identificeren en bewezen oplossingen implementeren. Neem contact op of voer een gratis benchmark uit om je huidige TTFB te zien.

Hulp nodig bij het verbeteren van je TTFB?

Wij auditen je serverinfrastructuur en implementeren optimalisaties die de responstijden drastisch verlagen.