Regex for URLs: finding links without overreaching
A URL regex is for finding candidate links in text, not for validating them. The preset requires an http or https scheme and a dotted hostname, and hands the result to a parser.
At a glance
- Built in preset
- URL
- Preset pattern
- https?://[\w.-]+(?:\.[a-zA-Z]{2,})(?:/[\w./?#&=%-]*)?
- Preset flags
- g and i
- Requires
- an http or https scheme and a host with a dotted suffix
- Does not match
- localhost, a bare host with a port, IPv6 literals, or schemeless links
- Better final check
- hand the candidate to a URL parser
In detail
Link detection and URL validation are different problems and only the first one suits a regular expression. Finding a candidate in a paragraph of prose means guessing where the link stops, which is a judgement call about punctuation rather than a question about syntax, and every implementation gets some of those calls wrong.
The preset takes a deliberately narrow position. It insists on a scheme, then a host of word characters, dots and hyphens, then a required dot and a suffix of two or more letters, then an optional path. That last requirement is why it does not match http://localhost:3000 at all: there is no dotted suffix, so the whole attempt fails rather than matching a prefix.
The port is a related casualty. Against https://example.com:8443/a the pattern matches only https://example.com, because a colon is not in the host class and not in the path class either. That is a limitation rather than a bug, and it is the kind of thing worth checking against your own data before adopting any link pattern wholesale.
The trailing punctuation problem is unavoidable in general and visible here. A sentence ending in a bare domain works correctly, because the final dot cannot be followed by two letters and the pattern backtracks out of it. A sentence ending in a path does not: the full stop is inside the path character class, so the pattern happily includes it. Trimming trailing punctuation from a candidate afterwards is the usual remedy.
Examples
const url = /https?:\/\/[\w.-]+(?:\.[a-zA-Z]{2,})(?:\/[\w./?#&=%-]*)?/gi;
"Visit https://example.com/page?q=1 or http://docs.test.org/api for more info."
.match(url);
// ["https://example.com/page?q=1", "http://docs.test.org/api"]const url = /https?:\/\/[\w.-]+(?:\.[a-zA-Z]{2,})(?:\/[\w./?#&=%-]*)?/i;
"http://localhost:3000".match(url); // null
"https://example.com:8443/a".match(url)[0]; // "https://example.com"
"see https://example.com.".match(url)[0]; // "https://example.com"
"see https://example.com/page.".match(url)[0];// "https://example.com/page."The trailing full stop is excluded after a bare domain and included after a path, because a full stop is a legal path character.
Things that catch people out
- The preset requires a dotted host, so it never matches localhost, an intranet hostname, or an IP address URL.
- A port is not matched, and the pattern silently returns the URL truncated at the colon rather than failing, which is worse than no match at all.
- A full stop at the end of a sentence is included when the URL has a path, so candidates need their trailing punctuation trimmed before use.
Try it: Regex Tester
Type a pattern and a test string, watch every match highlight as you go, read a plain English breakdown of each token, and check the numbered and named groups it captured.
Regex Tester
LOCAL · Browser-OnlyTest and debug regular expressions with live matching and highlights
Related Regex syntax
All regex syntax →Regex for email addresses: what can and cannot be validated
No regular expression fully validates an email address. Here is what the built in preset accepts, what it rejects, and the only check that settles it.
Regex for IPv4 addresses with real octet range checks
The naive four groups of digits pattern accepts 999.999.999.999. Here is the alternation that enforces 0 to 255, and the leading zero case it still allows.
Escaping metacharacters: which ones, and where
Twelve characters need escaping outside a character class and only four inside one. User input needs an escape function before it goes near new RegExp.
Regex for UUIDs: matching the 8-4-4-4-12 layout
The preset matches the hexadecimal layout of any UUID. Pinning it to version 4 takes two extra character classes, one for the version and one for the variant.
Regex for hex colours: three, six and eight digit forms
The built in preset matches the three and six digit forms and rejects the four and eight digit ones with alpha. Here is the pattern that covers all four.
Regex for ISO dates: matching YYYY-MM-DD without fake days
The preset rejects month 13 and day 32 with two alternations, and still accepts 2026-02-31. No regex can check a calendar, so parse and compare.
Tools for this
- Regex Tester Free online regex tester - test and debug regular expressions with live matching and highlights
- Regex Playground Regex playground with live match highlighting, named groups, find and replace, and shareable links