Complete Guide to Time to First Byte (TTFB)
Time to First Byte (TTFB) measures how long it takes for the browser to receive the first byte of a response from the server after making a request. It's the foundational performance metric -- the starting line from which all other metrics are measured. A good TTFB is 800 milliseconds or less.
TTFB isn't one of the three Core Web Vitals (LCP, CLS, INP), but it's arguably the most important diagnostic metric because it sets a hard floor for LCP. Your Largest Contentful Paint can never be faster than your TTFB, because the browser cannot render anything until it receives the HTML. If your TTFB is 1.5 seconds, your LCP will be at minimum 1.5 seconds -- and in practice, significantly higher.
What is Time to First Byte?
TTFB is the duration from the start of the navigation request to when the browser receives the first byte of the response. It encompasses everything that happens before the browser can begin parsing HTML:
- Redirect time: Time spent following HTTP redirects (e.g., http to https, www to non-www)
- DNS lookup: Resolving the domain name to an IP address
- TCP connection: Establishing the TCP connection (three-way handshake)
- TLS negotiation: Completing the HTTPS handshake (for secure connections)
- Request sent: Transmitting the HTTP request to the server
- Server processing: The server receiving the request, executing application logic, querying databases, rendering templates, and generating the response
- Response transit: The first byte of the response traveling from server to browser
Of these components, server processing time is typically the largest and most variable. DNS, TCP, and TLS are largely determined by geographic distance and can be minimized with CDNs. Server processing time depends entirely on your application architecture.
// Measure TTFB using the Navigation Timing API
const [nav] = performance.getEntriesByType('navigation');
const ttfb = nav.responseStart - nav.requestStart;
const serverTime = nav.responseStart - nav.requestStart;
const dnsTime = nav.domainLookupEnd - nav.domainLookupStart;
const tcpTime = nav.connectEnd - nav.connectStart;
const tlsTime = nav.requestStart - nav.secureConnectionStart;
console.log('TTFB:', nav.responseStart, 'ms');
console.log('Breakdown:', {
dns: dnsTime.toFixed(0) + 'ms',
tcp: tcpTime.toFixed(0) + 'ms',
tls: tlsTime.toFixed(0) + 'ms',
server: serverTime.toFixed(0) + 'ms',
});
// Or use the web-vitals library
import {onTTFB} from 'web-vitals';
onTTFB(({value}) => console.log('TTFB:', value, 'ms'));
TTFB thresholds
Unlike the three Core Web Vitals, TTFB thresholds are advisory rather than strict ranking factors. However, a TTFB above 800ms makes it extremely difficult to achieve a good LCP score (2.5s), so treating 800ms as a hard limit is prudent.
Why TTFB matters for performance
1. It's the floor for every other metric. Nothing can render until the first byte arrives. Every millisecond of TTFB is a millisecond added to FCP, LCP, and every other paint-based metric. A 500ms TTFB improvement translates directly to a 500ms LCP improvement, assuming nothing else changes.
2. It compounds with other bottlenecks. On a page with render-blocking CSS, the browser receives the HTML (TTFB), discovers the CSS file, requests it (another round trip), waits for the CSS response, and then renders. If your TTFB is 1 second and your CSS is on the same origin, you're looking at 1.5-2 seconds before any rendering begins.
3. It disproportionately affects mobile users. Mobile networks have higher latency than fixed broadband. A TTFB that measures 200ms on a fiber connection might be 800ms+ on a 4G connection, and 2+ seconds on a 3G connection in a developing market. CDNs mitigate this by reducing the physical distance between user and server.
Common causes of poor TTFB
1. No CDN (geographic distance)
Physics limits the speed of data transmission. Light in a fiber optic cable travels at approximately 200,000 km/s. A request from Sydney to a server in Virginia covers roughly 16,000km each way, resulting in a minimum round-trip latency of ~160ms just for the speed of light. In practice, routing adds 50-100ms more. Without a CDN, users far from your origin server face unavoidable high TTFB.
2. Slow server-side processing
Complex database queries, expensive template rendering, inefficient ORM usage, unoptimized API calls, and resource-intensive computation all extend server processing time. A WordPress site with 30 plugins, each running database queries on every page load, can easily spend 500ms+ generating a response that a cached version could serve in 5ms.
3. No server-side caching
Without caching, the server regenerates every page from scratch on every request. This includes querying the database, running application logic, rendering templates, and serializing the response. For content that doesn't change between requests (or changes infrequently), this is wasted computation that directly increases TTFB.
4. Redirect chains
Each HTTP redirect adds a full round trip. A chain of http://example.com -> https://example.com -> https://www.example.com -> https://www.example.com/en/ adds three unnecessary round trips before the actual page load begins. Each redirect can add 100-300ms depending on the connection.
5. Under-provisioned infrastructure
Servers running at high CPU or memory utilization queue incoming requests instead of processing them immediately. Shared hosting is especially prone to this because your site shares resources with hundreds of other sites. During traffic spikes, response times degrade rapidly without auto-scaling.
Step-by-step TTFB optimization
Deploy a CDN
A CDN is the single most impactful TTFB optimization. It serves cached responses from edge servers close to users, eliminating the round trip to your origin server. For static sites, a CDN can serve pages in under 50ms from any location globally. For dynamic sites, many CDNs support edge caching rules or edge compute (Cloudflare Workers, Vercel Edge Functions) to generate responses at the edge.
# CDN-friendly caching headers for static pages
Cache-Control: public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800
# s-maxage: CDN cache duration (1 day)
# max-age: browser cache duration (1 hour)
# stale-while-revalidate: serve stale while fetching fresh (7 days)
# For pages with user-specific content
Cache-Control: private, no-cache
Vary: Cookie
# CDN won't cache, but browser handles conditional requests
Implement server-side caching
Cache at every layer: full-page caching for anonymous visitors, fragment caching for page components, query caching for database results, and object caching for computed values. For WordPress, use a page caching plugin. For custom applications, implement caching with Redis or Memcached.
// Express.js: Simple full-page cache with Redis
import Redis from 'ioredis';
const redis = new Redis();
app.get('/blog/:slug', async (req, res) => {
const cacheKey = `page:${req.params.slug}`;
// Check cache first
const cached = await redis.get(cacheKey);
if (cached) {
return res.send(cached); // ~5ms TTFB
}
// Generate page (expensive)
const html = await renderBlogPost(req.params.slug);
// Cache for 1 hour
await redis.set(cacheKey, html, 'EX', 3600);
res.send(html); // ~200ms first request, ~5ms after
});
Optimize database queries
Database queries are usually the largest component of server processing time. Add indexes to columns used in WHERE, JOIN, and ORDER BY clauses. Use EXPLAIN to analyze slow queries. Implement connection pooling to avoid the overhead of creating new database connections per request. Consider read replicas for read-heavy workloads.
-- Identify slow queries
EXPLAIN ANALYZE
SELECT p.*, u.name as author
FROM posts p
JOIN users u ON p.author_id = u.id
WHERE p.published = true
AND p.category = 'performance'
ORDER BY p.created_at DESC
LIMIT 20;
-- Add composite index for this query pattern
CREATE INDEX idx_posts_published_category_date
ON posts (published, category, created_at DESC)
INCLUDE (author_id, title, slug, excerpt);
Use streaming SSR
Instead of waiting for the entire page to render on the server before sending any response, stream HTML to the browser as it's generated. The browser starts receiving and parsing HTML immediately, discovering resources and starting downloads while the server is still generating the rest of the page. This can reduce effective TTFB by 30-50% on pages with heavy server-side data fetching.
// Next.js App Router: streaming with Suspense
// The shell renders immediately, data streams in
import { Suspense } from 'react';
export default function BlogPage() {
return (
<main>
<Header /> {/* Renders immediately */}
<Suspense fallback={<ArticleSkeleton />}>
<ArticleContent /> {/* Streams when data is ready */}
</Suspense>
<Suspense fallback={<CommentsSkeleton />}>
<Comments /> {/* Streams independently */}
</Suspense>
</main>
);
}
Eliminate redirect chains
Audit your redirect chains and collapse them to a single redirect or eliminate redirects entirely. Configure your server to redirect directly to the final URL. Use HSTS preloading to eliminate http-to-https redirects for returning visitors.
# BAD: Chain of redirects (3 round trips)
# http://example.com -> https://example.com -> https://www.example.com
# GOOD: Single redirect to final URL
server {
listen 80;
listen 443 ssl;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
# HSTS: eliminate http->https redirect for returning visitors
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
Advanced TTFB optimization
Edge computing
Edge compute platforms (Cloudflare Workers, Vercel Edge Functions, Deno Deploy, Fastly Compute) run your server-side logic on edge nodes worldwide, combining the benefits of a CDN with the ability to generate dynamic responses. Instead of sending requests to a central origin server, the edge node handles the request with sub-50ms TTFB from any global location.
HTTP/3 and QUIC
HTTP/3 uses the QUIC transport protocol instead of TCP. QUIC establishes connections in a single round trip (0-RTT for repeat connections), compared to TCP's three-way handshake plus TLS negotiation. This can save 100-300ms on the initial connection, directly reducing TTFB. HTTP/3 also eliminates head-of-line blocking, improving performance on lossy mobile connections.
103 Early Hints
The 103 Early Hints HTTP status code lets the server send preliminary response headers before the final response is ready. The browser can start preloading critical resources (CSS, fonts, hero images) while the server is still generating the page. This doesn't reduce TTFB itself, but it reduces the effective time to render by parallelizing resource discovery with server processing.
HTTP/1.1 103 Early Hints
Link: </styles/main.css>; rel=preload; as=style
Link: </fonts/inter.woff2>; rel=preload; as=font; crossorigin
... server processes for 200ms ...
HTTP/1.1 200 OK
Content-Type: text/html
<!DOCTYPE html>
<html>...
stale-while-revalidate caching
The stale-while-revalidate Cache-Control directive lets CDNs serve stale content instantly while fetching a fresh copy in the background. This provides near-zero TTFB for returning visitors while ensuring content stays reasonably fresh. It's the best of both worlds: instant responses with eventual consistency.
Measuring TTFB accurately
TTFB varies significantly based on the user's location, network conditions, and server load. A TTFB that looks great from your office may be terrible for users in other regions.
Field measurement: Use the web-vitals library to collect real-user TTFB data. Segment by geography, device type, and connection type to identify populations with poor TTFB. CrUX (via PageSpeed Insights) provides TTFB data at the 75th percentile.
Lab measurement: WebPageTest lets you test from 40+ global locations with configurable connection speeds. Run tests from multiple locations to understand the geographic TTFB distribution. Pingdom, GTmetrix, and Lighthouse also report TTFB.
Synthetic monitoring: Set up automated tests from multiple regions running every 5-15 minutes to track TTFB over time. This catches server-side regressions, hosting issues, and traffic-related degradation before users notice.
Platform-specific TTFB optimization
Next.js: Use Static Site Generation (SSG) with generateStaticParams for content pages -- TTFB is near zero because pages are pre-rendered. For dynamic pages, use Incremental Static Regeneration (ISR) with revalidate to serve cached pages while regenerating in the background. Deploy on Vercel or use next start behind a CDN.
WordPress: Install a full-page caching plugin (WP Super Cache, WP Rocket, or LiteSpeed Cache). Use a managed WordPress host with built-in caching (Kinsta, WP Engine, Cloudways). Add Cloudflare as a CDN layer with page rules for caching. Disable WP-Cron in favor of a real system cron to eliminate per-request overhead.
Node.js / Express: Implement Redis-based full-page caching for anonymous visitors. Use connection pooling for database clients. Consider running behind Nginx as a reverse proxy with built-in caching and gzip compression. For heavy pages, implement streaming with renderToPipeableStream (React) or equivalent.
Static sites: Deploy on a CDN-native platform (Netlify, Cloudflare Pages, Vercel, AWS CloudFront + S3). Static sites have inherently excellent TTFB because there's no server-side processing -- the CDN serves pre-built HTML files directly from its edge network. This site (WebVitals.tools) achieves sub-50ms TTFB globally using this approach.
Frequently asked questions
Google recommends a TTFB of 800 milliseconds or less. While not an official Core Web Vital threshold, TTFB directly impacts LCP (which is a ranking factor). Sites targeting a "Good" LCP score of 2.5s need to keep TTFB well under 800ms to leave enough time for resource loading and rendering.
No. The three Core Web Vitals are LCP, CLS, and INP. TTFB is classified as a diagnostic metric -- it helps explain why LCP might be poor. Google tracks TTFB in CrUX and recommends optimizing it, but it does not have a direct weight in ranking algorithms the way Core Web Vitals do.
TTFB measures the complete time from navigation start to receiving the first byte: redirect time, DNS lookup, TCP handshake, TLS negotiation, HTTP request transmission, server processing, and the first byte traveling back to the browser. Of these, server processing time is usually the largest and most variable component.
A CDN caches your content on edge servers distributed globally. When a user makes a request, the nearest edge server responds instead of your origin server. This eliminates the round-trip latency to the origin. A user in Tokyo accessing a US-based origin (400ms+ TTFB) might get a response from a local CDN node in under 50ms.
Yes. A static site on shared hosting without a CDN can still have poor TTFB due to: slow server hardware, geographic distance to users, server resource contention, and lack of HTTP keep-alive connections. Always serve static sites through a CDN -- platforms like Cloudflare Pages, Netlify, and Vercel provide this automatically.
TTFB is a floor for LCP. The browser cannot discover, request, or render resources until it receives the HTML. If TTFB is 1.5s, LCP cannot be below 1.5s, and will typically be 2-3x higher after accounting for resource loading and rendering time. Every millisecond saved on TTFB directly reduces LCP by the same amount.
The stale-while-revalidate Cache-Control directive serves the cached (stale) response immediately while fetching a fresh version in the background. Users always get fast responses (cached TTFB of 10-50ms), and content stays fresh within the revalidation window. Without it, cache misses cause slow TTFB spikes as the server regenerates content. See our server response guide.
Static generation (SSG/ISR) achieves the lowest TTFB (10-50ms) because pre-built HTML is served directly from CDN edge nodes. Edge functions add 30-100ms for server-side computation. Use SSG for content pages (blog, docs, product listings) and edge functions only when you need real-time personalization or data that cannot be pre-rendered.
Fix TTFB in your framework
Step-by-step optimization guides for every major framework and platform:
Fix TTFB in Next.js
Edge runtime, ISR, caching headers, and middleware optimization.
FixFix TTFB in Vue
Nitro server, SSR caching, and CDN configuration for Nuxt.
FixFix TTFB in Angular
Universal SSR optimization, caching, and Angular CLI server tuning.
FixFix TTFB on Docker
Distroless images, multi-stage builds, layer caching, healthcheck warmup, and Cloud Run/ECS cold-start mitigation.
ComparisonCDN Comparison 2026
Cloudflare vs Fastly vs Akamai vs Bunny vs Vercel Edge benchmarked on PoP coverage, regional TTFB, and cache hit ratio.
ComparisonStatic vs SSR: Performance in 2026
SSG, ISR, SSR, and edge SSR compared on TTFB, LCP, hydration cost, and SEO. Pick the right rendering model.
GuideLCP Guide
TTFB is the floor for LCP -- improving TTFB directly improves LCP.
ComparisonWordPress vs Shopify Speed
TTFB comparison between WordPress hosting tiers and Shopify CDN.