Chrome gives IPv6 a 50ms head start, and nobody asked you (preview)

Every time you visit a website that supports both IPv4 and IPv6, Chrome tries the IPv6 address first. If it doesn’t connect within 300 milliseconds, Chrome quietly fires off an IPv4 connection too, and whichever wins, wins.

That 300ms timer isn’t there to protect you. At least, not all of it. About 50ms of it exists to nudge the entire internet toward IPv6, a decision Google made on behalf of billions of users and never really told anyone about. It’s been sitting in the code, unchanged, for 14 years.

The legitimate part first

The mechanism itself is called Happy Eyeballs, and it’s a genuinely good idea. In the bad old days, if a site advertised an IPv6 address but the user’s IPv6 connection was broken, the browser would sit there trying to connect over IPv6, hang for ages, and only then give up and try IPv4. We’re talking multi-minute hangs. Users would assume the site was down.

Happy Eyeballs fixes this. Try IPv6, but don’t wait around forever. If it’s not working, race IPv4 in parallel and take whichever responds. The RFC that describes this recommends a timer of 150 to 250 milliseconds before that fallback kicks in.

Chrome uses 300.

Where the extra 50ms comes from

The number isn’t an accident, and the engineer who wrote it said exactly why. In a 2012 post, Chromium network engineer William Chan (willchan) explained the design:

> “we will connect() to the IPv6 address, but start a 300ms timer to fallback quickly to connect() to IPv4. We use a fast fallback system rather than simply racing both IPv6 and IPv4 in order to give an edge to IPv6 since we want to encourage people to switch to IPv6.”

And, more bluntly:

> “we want to incentivize folks to adopt IPv6, so even if the IPv4 pathway may be faster, we debatably ought to give IPv6 a slight handicap (a timer) here to help with adoption.”

That’s the whole thing in his own words. Even if IPv4 is faster for you, Chrome will sit on its hands for an extra moment to let IPv6 try to win, because Google wants the web to move to IPv6. A colleague, Randy Smith, put it the same way in a 2016 net-dev thread: the point of the 300ms delay “is to try and incentivize web servers and the supporting ecosystem to support IPv6.”

So this isn’t a conspiracy theory pieced together from code comments. The people who built it have said, plainly, that the timer is a lever to push adoption.

How many people actually hit it

You might think 300ms is so generous that nobody ever waits the full time. But Chan’s own 2012 data showed that 9.77% of dual-stack connections on Mac were hitting that fallback timer. He was excited enough about that number to follow it with seven exclamation marks in his notes.

Nearly one in ten connections, paying a small tax so that IPv6 could have its handicap. The penalty per connection is tiny. Let’s be honest about that. 50ms above the RFC is not something you’ll consciously notice. And IPv6 adoption is genuinely good for everyone - the internet ran out of IPv4 addresses long ago, and the transition has to happen somehow. But it’s still a decision being made about your connection, in service of a campaign you were never told you’d enrolled in, by software you thought was just a browser.

The number that was never updated

Here’s the part that gets at the real issue. In 2016, researchers found that lowering the timer to 150ms achieves the same IPv6 preference with about 10% less penalty. The engineers discussed it. They never changed it.

The constant is still right there in the source: kIPv6FallbackTime = base::Milliseconds(300) in net/socket/transport_connect_job.h. And directly attached to it is a note from around 2011:

> “TODO(willchan): Base this off RTT instead of statically setting it.”

That TODO is a developer admitting the static number is the wrong way to do it, and that it should be based on actual round-trip time. It was written about 14 years ago. A 2025 academic paper presented at ACM IMC confirmed the 300ms is still present in every Chromium-based browser shipping today. That’s Chrome, Edge, Brave, Opera, and the rest of them.

And it doesn’t stop at browsers. Electron apps ship Chromium’s network stack wholesale, which means VS Code, Slack, Discord, Figma - much of the desktop software you have open right now - inherit the exact same kIPv6FallbackTime constant. The app developers can’t opt out; there’s no setting, no flag, no API. Close Chrome and the timer follows you into your text editor.

So a placeholder from 2011, flagged by its own author as needing fixing, is still making connection-quality decisions for billions of people in 2026.

No escape hatch

“But it’s just Chrome,” you cry. “Switch browsers.” Let’s see how that goes.


Engine / runtime Fallback delay RFC 8305 recommends Notes
Chromium (Chrome, Edge, Brave, Opera, Vivaldi) 300ms fixed 250ms Deliberately over spec; no resolution delay, no address interlacing
Gecko (Firefox desktop) 250ms fixed 250ms RFC-compliant
Gecko (Firefox mobile) 300ms fixed 250ms Matches Chromium despite being a different engine
WebKit (Safari desktop) dynamic, 50ms-2000ms 250ms Most RFC-complete: resolution delay plus address interlacing
WebKit (Mobile Safari/iOS) dynamic, 50ms-1000ms 250ms Same implementation, narrower range
WebView2 300ms fixed 250ms Chromium-based
curl 200ms fixed 250ms Under spec, but below Chrome

Firefox on desktop follows the RFC at 250ms. Firefox on mobile? 300ms - the Chromium number, on an entirely different engine. Safari is the only browser that implemented the spec properly, with a dynamic delay based on actual network conditions, plus the resolution delay and address interlacing the RFC describes. Even curl, famously maintained by one Swedish guy, manages 200ms.

Which delivers the uncomfortable punchline: the engine that deviated least from the standard is the one locked to Apple hardware. The engine that deviated most is the one running the overwhelming majority of the web, plus WebView2 and every Electron app on your machine.

In a market with real engine diversity, a constant that’s deliberately over spec would be a liability. Some competitor would ship a faster fallback, benchmark it, and make noise about it. Instead, one team’s 2011 placeholder propagates to billions of devices, and there’s no mechanism - market, standards body, or otherwise - that can make it change. The RFC recommends 250ms. Chromium ships 300. And that’s that.

The bit that should make you pause

When this timer was set, IPv6 adoption was hovering near zero. The incentive made a kind of sense. Push the ecosystem, eat a small cost, move the web forward. IPv6 adoption now sits around 45% globally. The world it was designed to nudge has changed enormously. The number hasn’t moved an inch.

This is Google’s pattern, and to be fair the outcomes are often good. They invented SPDY and QUIC, deployed them through Chrome to force the industry’s hand, and both eventually became open standards everyone benefits from. Good results. Unilateral method. The same playbook drives AMP, with rather less happy results.

The IPv6 timer is at the gentle end of all this. It’s not malicious, it’s not even really harmful, and the underlying Happy Eyeballs mechanism is something every browser should have. The problem is narrower and harder to dismiss. An entity controlling the connection logic for most of the planet’s web traffic - and, through Electron, most of its desktop software - baked an adoption agenda into how your packets get routed, set the dial 50ms past what the standards body recommended, told almost nobody, and then left a 2011 placeholder running the show for a decade and a half.

When you have that much power over the web, the careless decisions matter as much as the careful ones.