URL Structure — What You Are Matching
A URL has up to 8 components: scheme://userinfo@host:port/path?query#fragment. Most web URLs only use 4–5 of these, but a good URL regex must handle all of them:
- Scheme (
https,http,ftp) — always present in absolute URLs - Host — domain name or IP address, with optional subdomains
- Port — optional, e.g.
:8080or:443 - Path — optional, e.g.
/blog/my-post - Query — optional, e.g.
?page=2&sort=date - Fragment — optional, e.g.
#section-3
Patterns for Common Use Cases
1. Simple HTTP/HTTPS validation
// Good for: form inputs that should be an http/https URL
const HTTP_URL = /^https?:\/\/[^\s$.?#].[^\s]*$/i;
HTTP_URL.test('https://example.com'); // true
HTTP_URL.test('http://sub.domain.co.uk/path'); // true
HTTP_URL.test('http://localhost:3000'); // true
HTTP_URL.test('ftp://files.example.com'); // false (ftp not allowed)
HTTP_URL.test('not a url'); // false2. HTTP + HTTPS + FTP
const ANY_URL = /^(?:https?|ftp):\/\/[^\s$.?#].[^\s]*$/i;3. Extract all URLs from a block of text
// Global flag + match — returns an array of all URLs in the string
const extractUrls = (text) =>
text.match(/https?:\/\/[^\s<>"\{\}|\\^[\]]+/gi) ?? [];
extractUrls('Visit https://example.com or http://test.org/path?q=1');
// => ['https://example.com', 'http://test.org/path?q=1']4. Extract domain from a URL
// Extract just the domain (without www prefix)
const getDomain = (url) =>
url.match(/^(?:https?:\/\/)?(?:www\.)?([^\/:?#]+)/i)?.[1] ?? null;
getDomain('https://www.example.co.uk/page'); // 'example.co.uk'
getDomain('http://sub.domain.org'); // 'sub.domain.org'5. Match URLs with specific extensions (images, PDFs)
// Image URLs
const IMAGE_URL = /^https?:\/\/.*\.(?:jpg|jpeg|png|gif|webp|svg)(\?.*)?$/i;
// PDF URLs
const PDF_URL = /^https?:\/\/.*\.pdf(\?.*)?$/i;Using the URL Constructor as a Fallback
For production validation, combine regex with the native URL constructor:
function isValidUrl(input) {
try {
const url = new URL(input);
return url.protocol === 'http:' || url.protocol === 'https:';
} catch {
return false;
}
}
// Advantage: handles edge cases (IDN, encoded chars) the regex misses
// Disadvantage: requires the full protocol — 'example.com' is invalidCommon Pitfalls
Missing global flag when extracting multiple URLs
/https?:\/\/.../ without the g flag only returns the first match. Always use /https?:\/\/.../g or /https?:\/\/.../gi when calling.match() on a multi-URL string.
Greedy matching consumes too much
When extracting URLs from HTML, [^\s]+ will also grab trailing punctuation like closing quotes or parentheses. Use a negative character class that excludes common HTML delimiters: [^\s<>"{}|\\^`[\]].
localhost and IP addresses
Simple domain regex patterns reject http://localhost:3000 and http://192.168.1.1. If your app needs to validate internal URLs, add localhost and IP ranges explicitly.