URL
Parses an absolute or relative URL string into a structured, mutable WHATWG URL object.
new URL(input[, base])- Added in Node.js v7.0.0, v6.13.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$input | string | The absolute or relative input URL to parse. If input is relative, then base is required. If input is absolute, the base is ignored. If input is not a string, it is converted to a string first. |
$baseoptional | string | The base URL to resolve against if the input is not absolute. If base is not a string, it is converted to a string first. |
Return value
URLA URL object whose components (protocol, host, pathname, search, hash) are readable and writable.
Errors
Throws a TypeError with code ERR_INVALID_URL when input (resolved against base) is not a valid absolute URL.
Changelog
- PHP v10.0.0The class is now available on the global object, so require('node:url') is no longer needed to use it.
- PHP v20.0.0, v18.17.0The ICU requirement was removed, so internationalized hostnames parse on small-ICU builds too.
URL is Node's implementation of the WHATWG URL Standard — the same parser browsers use. Construction is pure string work: nothing is fetched, no DNS lookup happens, and no network permission is required.
When to reach for it
Use it any time you need to take a URL apart, build one safely, or resolve a relative reference. The two-argument form is the reason it exists: new URL('/v3/items', base) applies the same resolution rules a browser uses for a link on a page, which is far more reliable than string concatenation or path.join().
What trips people up
The constructor throws on invalid input rather than returning null. A bare 'example.com/a' has no scheme, so it is not an absolute URL and it throws — pass a base or prepend https://. If you only want a yes/no answer, use URL.canParse() instead of wrapping the constructor in a try/catch.
Parsing also normalizes: the scheme and host are lowercased, default ports are dropped, dot segments are collapsed, and unsafe characters are percent-encoded. So new URL('HTTPS://Example.COM/a b').href is 'https://example.com/a%20b'. Compare href values, never the original strings.
Example
When to use it
- Pull the tenant id out of an incoming request URL without regex
- Resolve a relative Location header against the request URL during a redirect
- Build an API endpoint by setting pathname and search on a copy of a base URL
- Normalize user-submitted links before storing them so duplicates collapse
Frequently asked questions
Do I need to require('url') to use new URL in Node?
No — URL has been a global since Node 10, so you can call new URL() anywhere without importing anything. The node:url module is only needed for the helpers such as fileURLToPath(), pathToFileURL() and domainToASCII().
Why does new URL('example.com') throw Invalid URL?
Because a string with no scheme is a relative reference, not an absolute URL, and the constructor requires an absolute result. Either prepend the scheme ('https://example.com') or pass a base as the second argument.
Does creating a URL object make a network request?
No. Parsing is entirely local string processing — no DNS resolution, no connection, and no permission needed. A URL object only describes an address; you still need fetch or http to contact it.
More examples
Mutating components writes back to href
Every component is a live setter: assigning to pathname, port or hash re-serializes href immediately. host includes the port (example.com:8080) while hostname would not, and origin drops the path entirely — useful for CORS checks.
const u = new URL('https://example.com/v1/users?limit=10');
u.pathname = '/v2/users';
u.port = '8080';
u.searchParams.set('limit', '50');
u.hash = 'top';
console.log(u.href);
console.log(u.host);
console.log(u.origin);Safely deciding whether a redirect stays on your host
Shows the open-redirect trap. The protocol-relative '//evil.example.net' looks like a path but resolves to a different host, so origin comparison rejects it — a substring check like candidate.startsWith('/') would have let it through.
const base = 'https://app.example.com/dashboard';
function isSameOrigin(candidate) {
try {
return new URL(candidate, base).origin === new URL(base).origin;
} catch {
return false;
}
}
console.log(isSameOrigin('/settings'));
console.log(isSameOrigin('https://app.example.com/settings?x=1'));
console.log(isSameOrigin('https://evil.example.net/steal'));
console.log(isSameOrigin('//evil.example.net/steal'));Username, password and non-special schemes
The parser handles any scheme, not just http(s), so connection strings can be decomposed with it. Note the last line: mailto: is a non-special scheme, so there is no host and the whole address lands in pathname.
const u = new URL('postgres://carol:[email protected]:5432/appdb?sslmode=require');
console.log(u.protocol, u.username, u.password);
console.log(u.hostname, u.port, u.pathname.slice(1));
console.log(u.searchParams.get('sslmode'));
console.log(JSON.stringify(new URL('mailto:[email protected]').pathname));
Discussion