IPv4 address regex
Strict IPv4 that rejects out-of-range octets like 999.999.999.999.
^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/What it matches
The naive IPv4 pattern `\d{1,3}(\.\d{1,3}){3}` matches `999.999.999.999` — clearly not a real address. This pattern uses an alternation per octet to enforce the 0-255 range: `25[0-5]` (250-255), `2[0-4]\d` (200-249), or `[01]?\d\d?` (0-199 including optional leading zero). Each of the four octets gets the same check.
Examples
Matches
1.1.1.1Cloudflare DNS — minimal valid form.
192.168.0.255Common private-network range, max final octet.
255.255.255.255Broadcast address — all octets at maximum.
0.0.0.0All-zeros is valid (often `bind to all interfaces`).
Does not match
256.0.0.1First octet exceeds 255.
1.1.1.1.1Five octets instead of four.
192.168.1Three octets — IPv4 needs exactly four.
abc.def.ghi.jklNon-numeric.
192.168.001.001Leading zeros (technically valid in some parsers, often rejected as ambiguous).
Edge cases & gotchas
- Accepts leading zeros in octets (`010.0.0.1`). Some systems interpret leading zeros as octal — strip with `.replace(/\b0+(\d)/g, '$1')` if octal interpretation worries you.
- Doesn't distinguish public from private ranges. `10.0.0.0/8`, `172.16.0.0/12`, and `192.168.0.0/16` are all RFC 1918 private space; this pattern matches all of them.
- Doesn't accept IPv4-in-IPv6 form (`::ffff:1.2.3.4`). Use a separate IPv6 pattern or a parser.
- Doesn't enforce that the address is reachable. `0.0.0.0` and `255.255.255.255` are valid shapes but rarely what an end-user typed.
In your language
// JavaScript
const re = /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
const match = "input".match(re);All 13 languages (including Bash, Perl, Kotlin, Swift) available in the full toolkit Export tab.
Notes for production
- If you're using Node.js, `net.isIPv4(s)` from the `net` module is the right call for real validation — no regex needed.
- In Python, `ipaddress.IPv4Address(s)` raises `ValueError` on invalid input — also better than regex for one-off checks.
Frequently asked
Why does my pattern accept invalid IPs like 999.0.0.0?
Because the lazy version `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}` doesn't bound each octet. The strict pattern shown here uses an alternation per octet to enforce 0-255.
How do I match IPv6 with this?
You can't — IPv6 is a completely different format (eight groups of four hex digits, with various compression rules). The IPv6 regex is famously long; use a parser instead.
Should I use this for security-sensitive filtering?
For format validation, yes. For deciding 'is this a private IP I should block egress to', use a real parser plus a private-range table — regex can't do CIDR math.