[ GF.dev ] All Tools →

HTTP Response Headers: What Your Server Is Telling Browsers

Published 2026-03-29 · Last modified 2026-03-29

Every time your server responds to a request, it sends a set of HTTP headers before the actual content. These headers are instructions — they tell browsers how to cache the response, what encoding was used, whether the connection should stay alive, and much more. Misconfigured headers silently degrade performance, break caching, and expose security vulnerabilities. This article walks through every header that matters, explains what each one does, and shows you how to configure them correctly.

Viewing Your Server's Headers

Before optimizing, you need to see what you're working with. Use the GF.dev HTTP Headers Test to inspect the full response headers for any URL. You can also use curl from the command line:

curl -I https://example.com

The -I flag sends a HEAD request and displays only the headers. For a more detailed view including timing information:

curl -w "TTFB: %{time_starttransfer}s\n" -o /dev/null -s https://example.com

Performance-Critical Headers

Cache-Control

The most impactful header for performance. Cache-Control dictates how browsers and intermediary caches store and reuse responses. A well-configured Cache-Control header can eliminate the majority of requests to your origin server.

Key directives:

Example for a static CSS file:

Cache-Control: public, max-age=31536000, immutable

Example for a dynamic HTML page:

Cache-Control: public, max-age=0, s-maxage=3600, stale-while-revalidate=60

Content-Encoding

This header confirms that the server compressed the response body. Without compression, text-based assets (HTML, CSS, JavaScript, JSON, SVG) transfer at their full size, wasting bandwidth and slowing page loads.

Modern options:

In Nginx, enable both:

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;

# For Brotli (requires ngx_brotli module)
brotli on;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;

If the HTTP Headers Test doesn't show a Content-Encoding header for your HTML pages, compression isn't active and you're leaving easy performance gains on the table.

ETag and Last-Modified

These headers enable conditional requests — one of the most elegant caching mechanisms in HTTP. When a browser has a cached copy with an ETag, subsequent requests include If-None-Match: "etag-value". If the content hasn't changed, the server returns 304 Not Modified with no body, consuming minimal bandwidth.

Most web servers generate these automatically for static files. For dynamic content, you'll need to generate them in your application code.

Connection and Keep-Alive

HTTP/1.1 uses Connection: keep-alive by default, meaning the TCP connection persists across multiple requests. This avoids the overhead of a new three-way handshake for every asset. If you see Connection: close, something is misconfigured — likely a proxy or load balancer terminating connections prematurely. In HTTP/2 and HTTP/3, connection management is handled at the protocol level, and this header is obsolete.

Security Headers That Affect Performance

Strict-Transport-Security (HSTS)

While HSTS is a security header (covered in our SSL/TLS guide), it has a direct performance benefit: once a browser has seen the HSTS header, it will never attempt an insecure HTTP connection to your domain. This eliminates the HTTP → HTTPS redirect that otherwise adds 100–300 ms to the first request. Configure it as:

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

Content-Security-Policy

An overly permissive CSP doesn't hurt performance, but a well-crafted one can prevent unauthorized scripts from loading — scripts that might otherwise consume bandwidth and CPU cycles. CSP won't speed up your server, but it can prevent performance degradation from injected resources.

The Server Header: Information Leakage

The Server header exposes your web server software and version. While it doesn't affect performance, it's a security concern we've dedicated a full article to: Server Signature Exposure: Why You Should Hide Your Server Version. Check yours with the Server Signature Test.

Headers to Remove

Several default headers provide no benefit and should be stripped:

Configuring Headers in Nginx

Here's a practical Nginx configuration block that implements the recommendations above:

# Performance headers
add_header Cache-Control "public, max-age=3600" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# Remove information leakage
server_tokens off;
proxy_hide_header X-Powered-By;

# Static assets with long cache
location ~* \.(css|js|woff2|png|jpg|webp|svg|ico)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

Putting It All Together

HTTP headers are the control plane of web performance. Misconfigured caching headers alone can multiply your server's traffic by 10x, as browsers re-request resources they should have cached locally. Regularly audit your headers using the HTTP Headers Test and cross-reference with the TTFB Test to see the real-world impact of your changes.

For a complete performance troubleshooting methodology that encompasses headers alongside TTFB optimization, network diagnostics, and caching strategies, see our Web Server Performance Troubleshooting pillar guide.