惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
Engineering at Meta
Engineering at Meta
小众软件
小众软件
I
InfoQ
有赞技术团队
有赞技术团队
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Martin Fowler
Martin Fowler
月光博客
月光博客
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
Y
Y Combinator Blog
V
Visual Studio Blog
博客园 - 叶小钗
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
GbyAI
GbyAI
P
Proofpoint News Feed
Apple Machine Learning Research
Apple Machine Learning Research

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
IPv4 vs IPv6 in 2026 — what every developer should know
Vix · 2026-06-19 · via DEV Community

IPv4 vs IPv6 in 2026 — what every developer should know

For most of the last decade, IPv6 felt like a topic you could safely ignore. "Still mostly IPv4 out there" was a reasonable excuse. That excuse stopped being true in 2026.

In March 2026, native IPv6 access to Google exceeded 50% globally for the first time in the 18 years Google has tracked this data. Around the same time, IPv6 overtook IPv4 as the majority protocol for global internet traffic as a whole. If you're building anything that touches the network — a backend service, a mobile app, an IoT device — this is no longer a future problem. It's a today problem.

This article covers what changed, why it matters for how you write code, and practical examples for detecting and handling both protocols correctly.


Why this happened now

IPv6 has existed since 1998. The slow adoption for most of its life wasn't a technical failure — it was an economic one. IPv4 addresses, while exhausted, kept getting recycled, traded, and NAT'd around for years longer than anyone expected. Migrating an entire network stack costs money and carries risk; as long as IPv4 kept limping along, there was no urgent reason to switch.

Three forces changed the calculus:

Mobile carriers went IPv6-first. Akamai data shows 88.4% of T-Mobile's network running on IPv6, with AT&T at 74% and Verizon at 74.8%. Most phone users today are on IPv6 without knowing it.

IoT made IPv4 impractical at scale. The number of IoT devices grew from roughly 15 billion in 2015 to over 75 billion in 2025, and these devices increasingly default to IPv6 because it removes the need to manage NAT rules and port forwarding for every single device.

Adoption is wildly uneven by country. France sits at 73% IPv6 adoption, India at 72%, Saudi Arabia at 65% — while Italy is at 17%, Spain at 10%, and Egypt at 4%. If your users are concentrated in IPv6-heavy regions, you're already serving majority-IPv6 traffic whether you've planned for it or not.


What actually changes for you as a developer

IPv6 isn't "IPv4 but longer." A few practical differences matter immediately:

No more NAT assumptions. With IPv4, most consumer devices sit behind NAT, so the IP you see is shared across a household or office. With IPv6, every device commonly gets its own globally routable address. This changes how you think about rate limiting, abuse detection, and geolocation — one IP no longer reliably maps to "one network", it often maps to "one device."

Address format is different everywhere. 2001:db8::1 instead of 203.0.113.42. This breaks naive regex validation, log parsers, and URL construction (IPv6 literals in URLs need brackets: https://[2001:db8::1]:8080/).

Dual-stack is the norm, not the exception. Most networks today run both protocols simultaneously. Your server, your client libraries, and your monitoring all need to handle a connection coming in on either protocol gracefully — not as an edge case.


Detecting IPv4 vs IPv6 in your stack

Here's how to handle both protocols correctly across common languages and frameworks.

JavaScript / Node.js

function getIPVersion(ip) {
  if (ip.includes(':')) return 'IPv6';
  if (ip.includes('.')) return 'IPv4';
  return 'unknown';
}

// Express middleware to log both correctly
app.use((req, res, next) => {
  const ip = req.ip; // may be IPv4 or IPv6 depending on connection
  console.log(`${getIPVersion(ip)} request from ${ip}`);
  next();
});

A common bug: Express and many proxies report IPv4 addresses as IPv6-mapped, like ::ffff:203.0.113.42. Strip the prefix before doing anything with it:

function normalizeIP(ip) {
  if (ip.startsWith('::ffff:')) {
    return ip.substring(7); // back to plain IPv4
  }
  return ip;
}

Python

import ipaddress

def get_ip_version(ip: str) -> str:
    try:
        addr = ipaddress.ip_address(ip)
        return f"IPv{addr.version}"
    except ValueError:
        return "invalid"

print(get_ip_version("203.0.113.42"))      # IPv4
print(get_ip_version("2001:db8::1"))       # IPv6

ipaddress is in the standard library and handles validation, version detection, and even subnet math — no need for regex.

Go

package main

import (
    "fmt"
    "net"
)

func getIPVersion(ipStr string) string {
    ip := net.ParseIP(ipStr)
    if ip == nil {
        return "invalid"
    }
    if ip.To4() != nil {
        return "IPv4"
    }
    return "IPv6"
}

func main() {
    fmt.Println(getIPVersion("203.0.113.42"))  // IPv4
    fmt.Println(getIPVersion("2001:db8::1"))   // IPv6
}

PHP

function getIPVersion(string $ip): string {
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        return 'IPv4';
    }
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
        return 'IPv6';
    }
    return 'invalid';
}


Detecting client IP and protocol from the browser

If you need to know whether your visitor is reaching you over IPv4 or IPv6 (useful for diagnostics, dual-stack debugging, or simply curiosity), the cleanest approach is hitting protocol-specific endpoints — not parsing user agent strings or making assumptions.

IPPubblico.org exposes dedicated subdomains for exactly this:

// Forces an IPv4-only connection and returns the IPv4 address
fetch('https://ipv4.ippubblico.org/')
  .then(res => res.text())
  .then(ip => console.log('IPv4:', ip.trim()));

// Forces an IPv6-only connection — fails gracefully if the client has no IPv6
fetch('https://ipv6.ippubblico.org/')
  .then(res => res.text())
  .then(ip => console.log('IPv6:', ip.trim()))
  .catch(() => console.log('No IPv6 connectivity'));

Or get both in one call:

fetch('https://ippubblico.org/?text=1')
  .then(res => res.text())
  .then(text => {
    const lines = text.trim().split('\n');
    console.log(lines[0]); // IPv4: x.x.x.x or NONE
    console.log(lines[1]); // IPv6: x or NONE
  });

This pattern is genuinely useful: if ipv6.ippubblico.org times out or fails, you know definitively that the client has no IPv6 path to the public internet — not just that your app didn't request it.


Common pitfalls

Storing IPs as 32-bit integers. A classic IPv4-era optimization that breaks completely with IPv6. If your schema has an INT UNSIGNED column for IP storage, it cannot hold an IPv6 address. Use VARCHAR(45) or a native INET/CIDR type if your database supports one (PostgreSQL does).

Regex-based IP validation. Most handwritten IPv4 regexes don't even attempt IPv6, and IPv6's flexible notation (leading zero compression, :: shorthand, embedded IPv4) makes a correct regex genuinely hard to write by hand. Use your language's built-in IP parsing library instead — ipaddress in Python, net.ParseIP in Go, inet_pton in C, FILTER_VALIDATE_IP in PHP.

Rate limiting by IP alone. Since IPv6 commonly gives each device its own address while IPv4 often shares one address across many users behind NAT, identical rate-limiting logic produces very different real-world behavior depending on which protocol a request arrives on. A single aggressive IPv6 client looks like one bad actor; a misbehaving app on a shared IPv4 NAT can look like — and inadvertently punish — hundreds of innocent users at once.

CIDR notation differences. IPv4 subnets you're used to (/24, /16) map to wildly different scales in IPv6, where /64 is the standard allocation for a single network segment — already larger than the entire IPv4 address space.


Should you do anything about this right now?

If your stack already uses standard library IP parsing and your database can store variable-length strings, you're probably fine technically — dual-stack support is mostly already there in modern frameworks by default.

What's worth auditing:

  • Any handwritten IP validation or parsing logic
  • Database columns storing IPs as fixed-size integers
  • Rate limiting or abuse detection logic that assumes IPv4-style address sharing
  • Log analysis tools or dashboards that choke on the longer IPv6 format
  • Any hardcoded assumption that "an IP" is 4 bytes

None of this requires a rewrite. It requires checking that the assumptions baked into older code still hold — and increasingly, for a majority of your traffic, they don't.


Quick reference

Task IPv4 IPv6
Example address 203.0.113.42 2001:db8::1
URL with port 203.0.113.42:8080 [2001:db8::1]:8080
Typical subnet /24 (256 addresses) /64 (≈1.8×10¹⁹ addresses)
NAT behavior Usually shared across users Usually one address per device
Detect with IPPubblico https://ipv4.ippubblico.org/ https://ipv6.ippubblico.org/

Conclusion

IPv6 crossing the 50% threshold in March 2026 is the kind of milestone that's easy to miss because nothing visibly "switched over" — there was no flag day, no announcement, just a slow curve that quietly crossed the midpoint. But for anyone writing code that touches the network, the practical implication is concrete: code that silently assumes IPv4 is now wrong for roughly half of real-world traffic, and that share is still climbing.

The fix isn't dramatic. Use your language's built-in IP libraries, store IPs as strings, and stop assuming one IP equals one user. The protocol your code runs on increasingly isn't your choice to make — it's the network's.


Have you run into IPv6-related bugs in production? Share them in the comments — the edge cases are usually the most instructive part.