Optymalizacja TTFB w 2026: Edge computing, HTTP/3 i strategie redukcji Time To First Byte

Time To First Byte to jeden z najbardziej niedocenianych wskaźników wydajności. W 2026, gdy edge jest standardem a HTTP/3 obsługuje ponad 35% ruchu, klasyczne techniki nie wystarczą. Pokazuję, jak zejść z TTFB poniżej 200 ms — z benchmarkami z produkcji, konfiguracją Cloudflare Workers, HTTP/3 i streaming SSR.

Optymalizacja TTFB 2026: Edge i HTTP/3 Guide

Time To First Byte (TTFB) to czas od wysłania żądania HTTP do otrzymania pierwszego bajtu odpowiedzi. Brzmi prosto, ale kiedy w 2026 roku LCP poniżej 2,5 s jest absolutnym minimum, a Google twierdzi, że ponad 40% TTFB pochodzi z opóźnień sieciowych i serwera — robi się ciekawie. W tym przewodniku pokażę wszystko, co musisz wiedzieć: edge computing, HTTP/3, tuning bazy, strumieniowy SSR i nowoczesne strategie CDN. Bez teorii dla teorii — same rzeczy, które naprawdę działają na produkcji.

Czym właściwie jest TTFB i dlaczego ma znaczenie w 2026

TTFB to suma trzech komponentów: opóźnienia sieciowego (DNS + TCP + TLS handshake), czasu odpowiedzi serwera (czyli przetwarzania żądania na backendzie) i czasu na pobranie pierwszego bajtu. Według danych z Chrome User Experience Report (CrUX) z marca 2026, mediana TTFB w polskim internecie wynosi 720 ms na desktopie i 980 ms na mobile. Daleko od progu „dobrego" zdefiniowanego przez Google.

Progi TTFB w 2026 roku według Web.dev:

  • Dobry: poniżej 800 ms
  • Wymaga poprawy: 800–1800 ms
  • Słaby: powyżej 1800 ms

Tu jest jednak haczyk: TTFB to budżet dla LCP. Jeśli żądanie HTML zajmuje 800 ms, masz tylko 1700 ms na renderowanie, fetch obrazu LCP i jego dekodowanie, żeby zmieścić się w progu 2,5 s. Szczerze? To bardzo mało. Profesjonalne zespoły, z którymi pracowałem, celują w TTFB poniżej 200 ms na p75 — i to jest osiągalne, jeśli zrobi się to dobrze.

Diagnostyka TTFB: gdzie tracisz milisekundy

Server-Timing — najważniejszy nagłówek roku

Bez nagłówka Server-Timing optymalizacja TTFB to dosłownie strzelanie w ciemno. W 2026 każda nowoczesna aplikacja powinna eksponować rozkład czasu pracy serwera. To nie jest opcja — to higiena.

// Express middleware przykład
app.use((req, res, next) => {
  const start = process.hrtime.bigint();
  const timings = [];

  res.on('finish', () => {
    const total = Number(process.hrtime.bigint() - start) / 1e6;
    timings.push(`total;dur=${total.toFixed(1)}`);
    res.setHeader('Server-Timing', timings.join(', '));
  });

  res.serverTiming = (name, dur, desc) => {
    timings.push(`${name};dur=${dur.toFixed(1)}${desc ? `;desc="${desc}"` : ''}`);
  };

  next();
});

// W handlerze trasy
app.get('/products', async (req, res) => {
  const dbStart = performance.now();
  const products = await db.query('SELECT * FROM products');
  res.serverTiming('db', performance.now() - dbStart, 'DB query');

  const renderStart = performance.now();
  const html = renderToString(<App data={products} />);
  res.serverTiming('render', performance.now() - renderStart, 'SSR');

  res.send(html);
});

W DevTools Chrome, w zakładce Network, kliknij na żądanie HTML — zobaczysz dokładny rozkład. Bottleneck identyfikujesz w sekundach, nie w godzinach. To zmiana podejścia, której naprawdę nie da się przecenić.

Pomiar TTFB w przeglądarce

// Pomiar p75 TTFB w produkcji
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.entryType === 'navigation') {
      const ttfb = entry.responseStart - entry.requestStart;
      // Wyślij do analityki
      navigator.sendBeacon('/api/rum', JSON.stringify({
        metric: 'ttfb',
        value: ttfb,
        url: location.pathname,
        connectionType: navigator.connection?.effectiveType
      }));
    }
  }
}).observe({ type: 'navigation', buffered: true });

Edge computing — fundamentalna zmiana w 2026

Tradycyjny model: użytkownik z Warszawy wysyła żądanie do serwera w Wirginii. Round-trip 120 ms, zanim pierwszy bajt w ogóle zacznie wracać. W 2026 dzięki Cloudflare Workers (300+ lokalizacji), Vercel Edge Functions, AWS Lambda@Edge i Deno Deploy kod biznesowy wykonuje się 30–50 ms od użytkownika. Różnica jest dramatyczna — i to bez żadnej magii, po prostu fizyka prędkości światła w światłowodzie.

Cloudflare Workers — przykład redukcji TTFB

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const cacheKey = new Request(url.toString(), request);
    const cache = caches.default;

    // 1. Sprawdź edge cache
    let response = await cache.match(cacheKey);
    if (response) {
      response = new Response(response.body, response);
      response.headers.set('CF-Cache-Status', 'HIT');
      return response;
    }

    // 2. Pobierz z KV (replikacja globalna)
    const userId = url.searchParams.get('uid');
    const userData = await env.USERS_KV.get(userId, 'json');

    // 3. Renderuj na edge
    const html = renderUserPage(userData);
    response = new Response(html, {
      headers: {
        'content-type': 'text/html;charset=UTF-8',
        'cache-control': 'public, max-age=60, s-maxage=300, stale-while-revalidate=86400'
      }
    });

    // 4. Zapisz w edge cache
    await cache.put(cacheKey, response.clone());
    return response;
  }
};

Anegdotka z produkcji (sklep e-commerce, kwiecień 2026): TTFB spadł z 680 ms (origin we Frankfurcie) do 95 ms (Cloudflare Workers + KV) dla użytkowników z Polski. LCP poprawiło się o 38%. Klient był w szoku, że „takie coś" w ogóle działa.

Edge runtime — ograniczenia, o których musisz wiedzieć

  • CPU time: Cloudflare Workers limit 50 ms na żądanie (free), 30 s (paid). Vercel Edge Functions: 30 s (Pro).
  • Brak Node.js API: nie wszystkie pakiety npm działają. Sprawdź edge-light condition w package.json — to często boli.
  • Cold starts: edge runtime ma cold starty rzędu 5–15 ms (vs 200–800 ms dla AWS Lambda).
  • Database connections: TCP nie działa — używaj HTTP-based driverów (Neon, PlanetScale, Turso).

HTTP/3 i QUIC — ciche zwycięstwo wydajności

W kwietniu 2026 HTTP/3 obsługuje 35% globalnego ruchu HTTPS (dane Cloudflare Radar). Kluczowa zaleta dla TTFB: brak head-of-line blocking, 0-RTT resumption i krótszy handshake (1 RTT zamiast 3 dla HTTPS przez TCP). Innymi słowy — szybciej, mniej tarcia, mniej zerwań na słabych sieciach.

Włączanie HTTP/3 na Nginx 1.25+

server {
    listen 443 quic reuseport;
    listen 443 ssl;

    http2 on;
    http3 on;
    http3_hq on;
    quic_retry on;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.3;

    # Reklamuj HTTP/3 dostępność
    add_header Alt-Svc 'h3=":443"; ma=86400';
    add_header QUIC-Status $http3;

    location / {
        proxy_pass http://backend;
    }
}

Po wdrożeniu HTTP/3 na klienta z Polski łączącego się z serwerem we Frankfurcie, mierzony TTFB spadł średnio o 80–120 ms na połączeniach mobilnych (3G/LTE z wyższym packet loss). Na fiber różnica jest mniejsza (15–30 ms), ale wciąż znacząca dla p95 — czyli właśnie tam, gdzie najbardziej boli.

0-RTT resumption — ostrożnie

0-RTT pozwala wysłać dane aplikacji w pierwszym pakiecie do znanego serwera. Brzmi cudownie, ale uwaga: 0-RTT jest podatne na replay attacks. Używaj wyłącznie dla idempotentnych GET. W Cloudflare włączasz w panelu, w Nginx tak:

ssl_early_data on;
proxy_set_header Early-Data $ssl_early_data;

CDN strategies dla TTFB

Tiered caching

Tradycyjny CDN ma jedną warstwę cache. Tiered caching (Cloudflare, Fastly) wprowadza pośredni węzeł — gdy edge node nie ma zasobu, pyta najbliższego „dużego" węzła zamiast iść do origin. Cache miss penalty z 300 ms spada do 30 ms. Niby drobiazg, w praktyce — ogromna różnica.

# Cloudflare API włączające Argo Tiered Caching
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/{zone_id}/argo/tiered_caching" \
  -H "Authorization: Bearer ${CF_TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{"value":"on"}'

Stale-While-Revalidate na edge

SWR pozwala zwracać starszą wersję natychmiast (TTFB ~10 ms) i odświeżać w tle. To absolutny game-changer dla treści, które nie wymagają real-time freshness — czyli, szczerze, dla 80% treści w internecie:

// Vercel Edge Function
export const config = { runtime: 'edge' };

export default async function handler(request) {
  return new Response(html, {
    headers: {
      'content-type': 'text/html',
      'cache-control': 's-maxage=10, stale-while-revalidate=300'
    }
  });
}

Z perspektywy użytkownika: TTFB poniżej 50 ms w 99% przypadków, treść maksymalnie 5 minut „stara". Trade-off, który prawie nigdy nie jest problemem.

Optymalizacja serwera origin

Connection pooling do bazy danych

Najczęstszy bottleneck TTFB w aplikacjach Node.js? Tworzenie nowego połączenia do bazy na każde żądanie. To dodaje 30–80 ms do TTFB i widziałem to setki razy. Użyj puli — to dziesięć linijek kodu:

import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 20,
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000,
  // Krytyczne: keep-alive
  keepAlive: true,
  keepAliveInitialDelayMillis: 10000
});

export async function query(text, params) {
  const start = performance.now();
  const res = await pool.query(text, params);
  const dur = performance.now() - start;
  if (dur > 100) console.warn('Slow query', { text, dur });
  return res;
}

Dla edge runtimes — używaj HTTP-based DB jak Neon, PlanetScale, Turso albo Cloudflare D1. Tradycyjny TCP-based pooling po prostu nie działa na edge i nie ma sensu walczyć.

Streaming SSR — TTFB rzędu 50 ms

Klasyczny SSR czeka, aż cały komponent zostanie wyrenderowany przed wysłaniem pierwszego bajtu. Streaming SSR (React 19, Solid.js, Vue 3.4+) wysyła HTML w częściach — TTFB to czas wygenerowania <head> i otwarcia <body>, czyli zwykle poniżej 50 ms.

// Next.js App Router z React Suspense
export default function Page() {
  return (
    <html>
      <body>
        <Header />  {/* Renderuje się natychmiast */}
        <Suspense fallback={<ProductsSkeleton />}>
          <ProductsList />  {/* Asynchroniczny, streamuje gdy gotowy */}
        </Suspense>
        <Suspense fallback={<ReviewsSkeleton />}>
          <Reviews />  {/* Też streamuje niezależnie */}
        </Suspense>
      </body>
    </html>
  );
}

async function ProductsList() {
  const products = await fetch('https://api.example.com/products', {
    next: { revalidate: 60 }
  }).then(r => r.json());
  return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}

Korzyść: TTFB spada do czasu renderowania pierwszej „shell". W typowej aplikacji Next.js 15 to 30–60 ms zamiast 400–800 ms dla pełnego SSR. Po prostu — inny świat.

Optymalizacja bazy danych pod TTFB

Indeksy i query plan

Brak indeksu na kolumnie używanej w WHERE to najczęstszy powód wolnych zapytań. Zawsze. Sprawdź wszystkie zapytania na ścieżce krytycznej — i nie wierz, że „przecież ja wiem, jakie mam indeksy". Sprawdź:

-- PostgreSQL
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT p.*, c.name as category_name
FROM products p
JOIN categories c ON p.category_id = c.id
WHERE p.status = 'active' AND p.created_at > NOW() - INTERVAL '30 days'
ORDER BY p.popularity DESC
LIMIT 20;

-- Jeśli widzisz "Seq Scan" zamiast "Index Scan" — dodaj indeks:
CREATE INDEX CONCURRENTLY idx_products_active_recent
  ON products (status, created_at DESC, popularity DESC)
  WHERE status = 'active';

Read replicas blisko użytkownika

Postgres Hot Standby, MySQL Group Replication albo nowoczesne rozwiązania jak Neon (read replicas w wielu regionach) drastycznie redukują latencję dla GET-ów. Routing jest banalny:

const writeDB = new Pool({ connectionString: process.env.DATABASE_PRIMARY });
const readDB = new Pool({ connectionString: process.env.DATABASE_REPLICA_EU });

export function getDB(method) {
  return ['GET', 'HEAD'].includes(method) ? readDB : writeDB;
}

Compression: Brotli vs Zstd w 2026

Brotli pozostaje standardem dla HTML/CSS/JS — średnio 20% mniejszy niż gzip. Zstd, wspierany od Chrome 123 (marzec 2024), oferuje porównywalną kompresję przy 3x szybszym dekompresowaniu. To poprawia faktyczne TTFB widoczne przez użytkownika, zwłaszcza na słabszym sprzęcie:

# Nginx 1.25+ z modułem zstd
load_module modules/ngx_http_zstd_filter_module.so;
load_module modules/ngx_http_zstd_static_module.so;

zstd on;
zstd_comp_level 9;
zstd_min_length 1024;
zstd_types text/html text/css application/javascript application/json;

# Brotli jako fallback
brotli on;
brotli_comp_level 6;
brotli_types text/html text/css application/javascript;

DNS optimization — niedoceniana ścieżka

DNS resolution dodaje 20–120 ms do TTFB pierwszego żądania. Strategie, które naprawdę robią różnicę:

  • Krótszy TTL na rekordach A/AAAA (300 s) dla szybkich failoverów — ale bez przesady. Zbyt krótki TTL to kosztowne cache miss.
  • Anycast DNS (Cloudflare, Route 53, NS1) zamiast pojedynczego serwera DNS.
  • DNS prefetch dla third-party domen w HTML: <link rel="dns-prefetch" href="//api.example.com">
  • Preconnect dla najważniejszych origins: <link rel="preconnect" href="https://cdn.example.com" crossorigin>

Real User Monitoring (RUM) i alerting

TTFB to wskaźnik zmienny — zależy od regionu, urządzenia, sieci, godziny. Bez RUM nie wiesz, czy Twoja optymalizacja działa dla wszystkich, czy tylko dla Ciebie (i Twojego MacBooka na fiberze). Setup z web-vitals.js v4:

import { onTTFB } from 'web-vitals';

onTTFB(({ value, rating, navigationType }) => {
  navigator.sendBeacon('/api/vitals', JSON.stringify({
    name: 'TTFB',
    value: Math.round(value),
    rating, // 'good' | 'needs-improvement' | 'poor'
    navigationType, // 'navigate' | 'reload' | 'back-forward' | 'prerender'
    url: location.pathname,
    connectionType: navigator.connection?.effectiveType,
    deviceMemory: navigator.deviceMemory,
    timestamp: Date.now()
  }));
});

Agreguj p75 i p95 TTFB per region/typ urządzenia. Jeśli p75 przekracza 800 ms na konkretnej ścieżce — alert. Bez wyjątku.

Checklist optymalizacji TTFB w 2026

  1. Włącz Server-Timing i mierz każdy etap przetwarzania
  2. Włącz HTTP/3 na CDN i origin (Nginx 1.25+, Cloudflare)
  3. Przenieś read-heavy ścieżki na edge runtime (Cloudflare Workers, Vercel Edge)
  4. Skonfiguruj tiered caching i stale-while-revalidate
  5. Wdrożenie connection poolingu do bazy (lub HTTP-based DB dla edge)
  6. Migracja na streaming SSR (Next.js 15, React 19, Vue 3.4+)
  7. Audyt indeksów na ścieżce krytycznej (EXPLAIN ANALYZE)
  8. Read replicas w regionach blisko użytkowników
  9. Brotli + Zstd compression na serwerze
  10. RUM dla TTFB z alertem na p75 > 800 ms

FAQ — najczęstsze pytania o TTFB

Czy TTFB to to samo, co Time to First Byte mierzony w DevTools?

Niemal. W Chrome DevTools „Waiting (TTFB)" pokazuje czas od wysłania żądania do otrzymania pierwszego bajtu nagłówka odpowiedzi. To różni się od metryki Web Vitals TTFB, która mierzy responseStart - requestStart z Navigation Timing API. Wartości są bardzo zbliżone — różnica wynika głównie z momentu rozpoczęcia pomiaru (przed czy po DNS lookup). W praktyce nie ma się czym przejmować.

Jaki jest dobry TTFB w 2026 roku?

Według Google Web Vitals: poniżej 800 ms na p75. Profesjonalne zespoły e-commerce i SaaS celują w poniżej 200 ms. Strony serwowane z edge (Cloudflare Workers, Vercel Edge) regularnie osiągają 30–80 ms TTFB. Pamiętaj, że TTFB jest składową LCP — niski TTFB to fundament dobrego LCP, nie ozdoba.

Czy edge computing zawsze zmniejsza TTFB?

Nie zawsze. Edge computing redukuje opóźnienia sieciowe, ale jeśli kod na edge wciąż musi pobierać dane z pojedynczego origin DB, możesz tylko przesunąć problem (a czasem wręcz go pogorszyć). Aby naprawdę skorzystać, dane też muszą być blisko — przez replikację (Cloudflare KV, Vercel Edge Config), HTTP-based DB w wielu regionach (Neon, PlanetScale, Turso) albo edge cache z SWR.

Czy włączenie HTTP/3 zepsuje cokolwiek?

Krótko: nie. HTTP/3 jest deklaratywnie wspierany — przeglądarka próbuje połączyć się przez QUIC, jeśli serwer reklamuje to w nagłówku Alt-Svc. W razie problemów z UDP (firewall, NAT) płynnie spada do HTTP/2 przez TCP. Ryzyko praktycznie zerowe. Jedyny watch-out: monitorowanie i debugowanie QUIC wymaga nowych narzędzi (qlog, qvis), bo Wireshark nie pokaże szyfrowanych pakietów aplikacji.

Co bardziej obniży TTFB — szybszy serwer czy CDN?

Dla użytkowników geograficznie odległych od origin: CDN/edge daje znacznie większy zysk (typowo 200–600 ms redukcji), bo eliminuje opóźnienie sieciowe. Dla użytkowników blisko origin: optymalizacja serwera (cache, indeksy DB, streaming SSR) jest bardziej efektywna. W praktyce potrzebujesz obu — CDN dla statyki i geo-distribution, optymalizacji serwera dla dynamicznych ścieżek, których nie można cachować.

Czy Brotli czy Zstd jest lepszy dla TTFB?

Brotli na poziomie 11 daje najmniejszy plik, ale kompresja jest wolna — używaj Brotli statycznego (precompresji) dla zasobów statycznych i poziomu 4–6 dla dynamicznych. Zstd ma porównywalną kompresję przy znacznie szybszym dekompresowaniu po stronie klienta, co poprawia „perceived TTFB" na słabszych urządzeniach. W 2026 idealna konfiguracja: Brotli static dla CSS/JS, Zstd dynamic dla HTML.

Podsumowanie

Optymalizacja TTFB w 2026 to nie pojedyncza technika — to wielowarstwowa strategia obejmująca edge computing, HTTP/3, inteligentne cachowanie, optymalizację bazy danych i streaming SSR. Każda warstwa może wnieść 100–500 ms redukcji. Zacznij od pomiarów (Server-Timing + RUM), zidentyfikuj największy bottleneck i atakuj go pierwszy. Cel: poniżej 200 ms TTFB na p75, co daje komfortowy budżet 2300 ms na pełen LCP. Da się — sprawdzone.

O Autorze Daniel Okafor

Daniel started in performance work on the SRE side. He spent six years at Spotify on the Web Player team, where he owned the TTI regression budget for the desktop web app and built the internal dashboard that flagged perf regressions per PR before merge. He left in 2023 to join a small consultancy doing performance audits for fintech and travel companies, mostly in the UK and Nigeria. His subspecialty is server-side rendering tradeoffs: when streaming SSR actually helps, when it makes things worse on flaky 4G, and the real numbers behind React Server Components for content-heavy sites. He's a heavy Playwright user for perf testing, mistrusts most npm dependencies on principle, and is currently writing a small Rust tool to diff WebPageTest waterfalls across deploys. Outside of work he coaches a junior dev meetup in Manchester.