Preconnect

Performance

Preconnect is a resource hint that asks the browser to open a connection (DNS, TCP and, for HTTPS, TLS) to a cross-origin host before the first request needs it, so that request skips the setup round trips. The browser may do only part of it, or skip it. Same-origin requests gain nothing.

12 min read Updated Aug 30, 2026

Full Explanation

Preconnect is a resource hint that asks the browser to open a connection to a cross-origin host before the first request to that host. The first request then does not pay for connection setup. You declare it with the preconnect keyword on a link element, or with the same keyword in a Link response header. The HTML Standard defines both paths (HTML Standard, link type "preconnect"). It moves the DNS lookup, the TCP handshake, and, for HTTPS, the TLS negotiation up front: "DNS+TCP for HTTP, and DNS+TCP+TLS for HTTPS origins" (MDN). It is a hint, not a directive. A user agent "should attempt to initiate a preconnect and perform the full connection handshake ... whenever possible, but is allowed to elect to perform a partial handshake (DNS only for HTTP, and DNS or DNS+TCP for HTTPS origins), or skip it entirely, due to resource constraints or other reasons". It is also not a fetch. The connection opens and parks, and nothing downloads until the page asks for it. It also gives no benefit for your own origin: "it has no benefit on same-origin requests because the connection is already open" (MDN). Browser support is not the constraint. The keyword works in all current engines: Chrome 46+, Firefox 39+, Safari 11.1+, Edge 79+ (HTML Standard). Judgement is the constraint, because every hint spends a connection.

How it works

Opening a connection to an HTTPS origin costs three steps. Each step is a round trip: resolve the name to an address, complete the TCP handshake, then negotiate TLS. web.dev puts the bill at "up to three round trips—and more in unoptimized cases" (web.dev). Preconnect moves that bill earlier, into time the browser would otherwise spend parsing HTML, so "resources will load more quickly because the setup process has already been completed by the time the browser requests them".

There are two ways to declare it. In markup, use a link element in the head, usually written <link rel="preconnect" href="https://cdn.example.com">. The keyword "is body-ok", so it is also valid later in the document. And "a user agent must not delay the load event for this link type". So a hint that never pays off cannot hold up the page. From the server, the same keyword travels in a response header, Link: <https://cdn.example.com>; rel=preconnect (MDN). The HTML Standard gives that header its own processing step. So it is not a vendor convention (HTML Standard).

What the browser then does is narrow, and worth knowing exactly. It obtains a connection for the target origin, and "this connection is obtained but not used directly. It will remain in the connection pool for subsequent use". Three details of that algorithm matter in practice. First, the URL must have an HTTP(S) scheme, and an empty href is ignored. Second, credentials shape what the pooled connection is good for. The algorithm sets useCredentials to true, and drops it to false only when crossorigin is Anonymous and the target is cross-origin. So a preconnect with crossorigin and one without do not produce the same connection. Third, how many connections to open per origin is "deferred to the user agent" (HTML Standard).

Why it matters for a CDN

A CDN is the canonical target for the hint. The HTML arrives from your own origin. Images, scripts and fonts come from cdn.example.com. So the first request to the CDN on every cold page load pays a full connection setup before a byte of content moves. That is setup latency. The page cannot overlap it with anything else, because nothing has been requested from that host yet. web.dev puts the saving at "100–500 ms by establishing early connections to important third-party origins", phrased as what you can achieve rather than what you will (web.dev). The saving lands once per origin per connection, not on every request.

Preconnect has a niche that preload does not fill: knowing where a resource comes from, but not what it is. web.dev names two cases a CDN user meets constantly. One is a versioned dependency URL you cannot write out at build time. The other is an image-CDN URL whose path "depends on media queries or runtime feature checks on the user's browser". In both cases, "the browser won't download the file until your page requests it, but at least it can handle the connection aspects ahead of time, saving the user from waiting for several round trips". Streaming media from another origin is the third case web.dev lists. Connect now, and start retrieving when your scripts are ready to process the stream.

For Largest Contentful Paint, get the order of preference right, because preconnect is not the first tool. web.dev ranks them. Best is that the LCP resource is "immediately discoverable" in the markup, with a fetchpriority value of "high" to signal its importance. Where that is not possible, a preload link with the same fetchpriority still starts the load as early as possible. And only "if neither of these options are available—because the exact resource will not be known until later in the page load—you can use preconnect on cross-origin resources to reduce the impact of the late discovery of the resource as much as possible" (web.dev). So preconnect does help an LCP image served from the CDN. But it removes the connection cost, not the discovery delay. If you know the URL, preload it.

What CDNs do

Preconnect executes in the browser, so a CDN cannot open the viewer's connection for them. What the edge can do is deliver the declaration sooner: as a Link response header, or as a 103 (Early Hints) informational response sent while the origin is still assembling the page. Code 103 is defined by RFC 8297. That RFC is Experimental rather than Standards Track. It "introduces an informational HTTP status code that can be used to convey hints that help a client make preparations for processing the final response" (RFC 8297). It is still the registered reference for 103 in IANA's HTTP Status Codes registry. RFC 8297's own examples are all rel=preload. The preconnect-over-103 pattern is documented by MDN instead, which shows Link: <https://cdn.example.com>; rel=preconnect in a 103 response (MDN, 103 Early Hints). Two limits travel with the mechanism: "these header fields only provide hints to the client; they do not replace the header fields on the final response". And browsers "only process the first early hints response", which "must be discarded if the request results in a cross-origin redirect".

  • Cloudflare: Early Hints is a per-zone toggle, off by default, under Speed > Settings > Content Optimization. It is available on Free, Pro, Business and Enterprise. "Cloudflare caches and serves these 103 responses with Link headers from your HTML pages, reducing user-perceived latency", emitting the cached 103 "ahead of a main response". Hints are only generated for URIs with .html, .htm or .php extensions or no extension, on 200, 301 or 302 responses. They are only generated "when the response contains link headers with preconnect or preload rel types". Two operational notes matter. Cache entries are keyed by request URI and ignore query strings. And because the 103 can be emitted before the request reaches your origin, "unauthenticated visitors may receive a 103 response" carrying cached Link headers ahead of a 403 (Cloudflare docs).
  • Fastly: "Fastly's platform has support for sending Early Hints in edge code. It is only effective for clients connecting using HTTP/2 or later." In VCL you "call the early_hints function" with Link header values, typically guarded on fastly_info.is_h2 or fastly_info.is_h3. In a Compute application you send a Response with status 103 to the client, and "any number of 103 Early Hints responses may be sent before sending the final response". "Fastly only supports 103 Early Hints over HTTP/2 or HTTP/3" (Fastly docs).
  • Akamai: Early Hints is a Property Manager behavior, supported "for use with Akamai's Ion and Dynamic Site Accelerator products". It sends "an HTTP 103 status code with preliminary HTTP headers at the client request stage, so that a browser can preload critical website resources or preconnect to a specific domain while waiting for the final HTML response". You put the header value in the Resource Hints field, for example <https://static1.example.com>;rel=preconnect. The field supports variables so EdgeWorkers can compute the list per request. "The Early Hints behavior is compatible with both HTTP/2 and HTTP/3 protocols. HTTP/1.1 protocol version is not compatible with the Early Hints behavior." The 103 is only sent when Sec-Fetch-Mode is navigate. Only the last instance of the behavior in a rule tree takes effect. And the 103 response header size defaults to 3 KB (Akamai docs).
  • CloudFront: neither the request and response behavior for custom origins page nor the response headers policies page mentions 103 or Early Hints. Read that as not documented rather than not supported.

Browser support for the 103 path, per MDN's compatibility data, is Chrome 103+, Firefox 120+ and Safari 17+. In each case, it is "supported in HTTP/2 and later only" (MDN). So the 103 route is far younger and narrower than the markup route. Akamai's documentation adds that Safari acts on preconnect but not preload from an early hint. MDN's data does not record that split. So treat it as vendor guidance rather than a settled fact.

Watch out for

  • Too many hints. "If a page needs to make connections to many third-party domains, preconnecting all of them is counterproductive. The preconnect hint is best used for only the most critical connections." The cost is real: "excessive preconnect hints still consume bandwidth where TLS certificates are concerned. Be careful not to preconnect to too many origins, as this may cause bandwidth contention", and "setting up and keeping a connection open is a lot of work" (web.dev). A connection the page never uses is pure cost.
  • The crossorigin attribute on CORS origins. Fonts are fetched in anonymous mode, so "for those you must set the crossorigin attribute with the preconnect hint". The reason is the credentials key in the algorithm: "CORS-protected resources must be fetched over a completely separate connection". So an origin from which you need both an image and a font needs two hints, one plain and one with crossorigin. If you need only one kind, "you only need to preconnect once" (MDN). Getting this wrong is silent. The page still works, it just opens the connection you did not preconnect.
  • Same-origin hints. They do nothing, because that connection is already open. "Preconnecting is only effective for domains other than the origin domain, so you shouldn't use it for your site" (web.dev).
  • Merging rel keywords. Do not write rel="preconnect dns-prefetch" on one link element: "implementing dns-prefetch fallback in the same <link> tag causes a bug in Safari where preconnect gets cancelled". web.dev's own remedy is to "use separate link tags" (web.dev).
  • Measuring it cross-origin. The connect phase is connectStart to connectEnd in Resource Timing. connectEnd "includes the time interval to establish the transport connection, as well as other time intervals such as TLS handshake". But it reads 0 "if the resource is a cross-origin request and no Timing-Allow-Origin HTTP response header is used" (MDN). That is exactly the case preconnect exists for. So set Timing-Allow-Origin on the CDN before you try to measure the hint.
  • The 103 route needs HTTP/2 or HTTP/3 in practice, though not by rule. RFC 8297 does not forbid HTTP/1.1. It warns in Security Considerations that a client mishandling an informational response as a final one "might constitute a cross-origin information disclosure vulnerability". It concludes that "a server might refrain from sending 103 (Early Hints) responses over HTTP/1.1 unless the client is known to handle informational responses correctly" (RFC 8297, section 3). Browsers and CDNs turned that caution into a hard limit. So treat HTTP/2 or later as the requirement, even though the RFC states it as a should-not.

Best practice

  • Hint only the origins the current page is certain to use. Keep the list to a handful. If you cannot name the resource you will fetch from an origin, that is the right reason to preconnect. If you can name it, preload it with fetchpriority="high" instead, and get the fetch as well as the connection.
  • Add crossorigin for font and other CORS origins. Add a second plain hint only if you also fetch non-CORS resources from that same host. Preconnecting a font origin without crossorigin is the most common way to get no benefit at all.
  • Use dns-prefetch for origins you are less sure about, or that a later navigation will need. It "doesn't establish a connection to a cross-origin server, but rather just performs the DNS lookup for it ahead of time", and DNS lookups "are fairly inexpensive" (web.dev). Keep it in its own link element. Do not confuse it with prefetch, which downloads a whole resource for a later navigation.
  • Where the edge can send the hint, send it from the edge. A Link response header, or a 103 Early Hints response, beats hand-maintaining link elements in every template. The 103 also buys the browser the origin's think time. Keep the markup hints for anything a viewer on HTTP/1.1 or an older browser still needs.
  • Measure the connect phase with and without the hint. Remember that a cross-origin resource reports zeros until the CDN sends Timing-Allow-Origin. Drop hints that do not move the number: "use preconnect only for the most important resources, rely on dns-prefetch for the rest, and always measure the impact in the real-world" (web.dev).

Examples

HTML resource hints:

<head>
    <!-- Preconnect to CDN (DNS + TCP + TLS) -->
    <link rel="preconnect" href="https://cdn.example.com">

    <!-- Preconnect to font provider -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    <!-- Fallback for browsers without preconnect -->
    <link rel="dns-prefetch" href="https://cdn.example.com">
</head>

Measuring preconnect impact:

# Without preconnect (Resource Timing API)
// connectStart to connectEnd includes TCP + TLS
performance.getEntriesByName('https://cdn.example.com/hero.jpg')[0]
// connectEnd - connectStart = 120ms

# With preconnect
// connectEnd - connectStart = 0ms (already connected)
// Saves ~120ms on first resource from that origin

Frequently Asked Questions

Preconnect is a resource hint that asks the browser to open a connection (DNS, TCP and, for HTTPS, TLS) to a cross-origin host before the first request needs it, so that request skips the setup round trips. The browser may do only part of it, or skip it. Same-origin requests gain nothing.

HTML resource hints:

<head>
    <!-- Preconnect to CDN (DNS + TCP + TLS) -->
    <link rel="preconnect" href="https://cdn.example.com">

    <!-- Preconnect to font provider -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    <!-- Fallback for browsers without preconnect -->
    <link rel="dns-prefetch" href="https://cdn.example.com">
</head>

Measuring preconnect impact:

# Without preconnect (Resource Timing API)
// connectStart to connectEnd includes TCP + TLS
performance.getEntriesByName('https://cdn.example.com/hero.jpg')[0]
// connectEnd - connectStart = 120ms

# With preconnect
// connectEnd - connectStart = 0ms (already connected)
// Saves ~120ms on first resource from that origin