node:url
require('url') The node:url module provides utilities for URL parsing, resolution, and manipulation. It supports both the legacy url.parse() API and the modern URL class that follows the WHATWG URL Standard. This module is essential for working with URLs in web servers, API clients, and any application that handles URLs.
The URL class (modern API)
The URL class provides a convenient and standards-compliant way to work with URLs.
Creating a URL Object
const { URL } = require('url');
const myURL = new URL('https://user:pass@example.com:8080/path/name?query=value#hash');
console.log(myURL.href);
// "https://user:pass@example.com:8080/path/name?query=value#hash"
console.log(myURL.protocol);
// "https:"
console.log(myURL.host);
// "example.com:8080"
console.log(myURL.hostname);
// "example.com"
console.log(myURL.port);
// "8080"
console.log(myURL.pathname);
// "/path/name"
console.log(myURL.search);
// "?query=value"
console.log(myURL.hash);
// "#hash"
console.log(myURL.username);
// "user"
console.log(myURL.password);
// "pass"
Modifying URL Components
Once you have a URL object, you can change any component by assigning to its properties—protocol, hostname, port, pathname, and search all update independently. The href getter always reflects the current state, so you can read it back after your changes to see the fully reassembled URL string.
const { URL } = require('url');
const url = new URL('https://example.com/path');
url.protocol = 'http:';
url.hostname = 'newhost.com';
url.port = '3000';
url.pathname = '/newpath';
url.search = 'key=value';
console.log(url.href);
// "http://newhost.com:3000/newpath?key=value"
Query string manipulation
The URL class includes a built-in searchParams property that gives you a full URLSearchParams API for reading, setting, appending, and deleting query parameters. This is far cleaner than manual string splitting and re-encoding, and it automatically handles edge cases like duplicate keys and percent-encoding.
const { URL } = require('url');
const url = new URL('https://example.com/search?q=javascript&page=1');
// Get all parameters
console.log(url.searchParams.get('q')); // "javascript"
console.log(url.searchParams.get('page')); // "1"
// Set parameters
url.searchParams.set('q', 'typescript');
url.searchParams.append('lang', 'en');
console.log(url.href);
// "https://example.com/search?q=typescript&page=1&lang=en"
// Delete parameters
url.searchParams.delete('page');
console.log(url.href);
// "https://example.com/search?q=typescript&lang=en"
Legacy API
The legacy API uses url.parse() and url.format() functions.
Parsing a URL
The legacy url.parse() function takes a URL string and returns a plain object with each component split out. While it works for simple cases, it does not follow the WHATWG standard and handles edge cases like empty hostnames and IPv6 addresses differently than the URL class.
const url = require('url');
const parsed = url.parse('https://user:pass@example.com:8080/path?q=1#hash');
console.log(parsed);
// {
// protocol: 'https:',
// auth: 'user:pass',
// hostname: 'example.com',
// port: '8080',
// path: '/path?q=1',
// pathname: '/path',
// query: 'q=1',
// hash: '#hash'
// }
Resolving relative URLs
The legacy url.resolve() method resolves a relative path against a base URL, handling directory traversal (..) and absolute path overrides automatically. While it still works, the WHATWG URL constructor with a base argument is the preferred replacement for new code.
const url = require('url');
console.log(url.resolve('/one/two', 'three'));
// "/one/three"
console.log(url.resolve('/one/two/', 'three'));
// "/one/two/three"
console.log(url.resolve('http://example.com/', '/one'));
// "http://example.com/one"
console.log(url.resolve('http://example.com/a', '../b'));
// "http://example.com/b"
Examples
Building URLs from parts
When you need to construct a URL programmatically from a base path and a set of query parameters, the URL class and searchParams API let you build it cleanly without manual string concatenation. This approach avoids encoding pitfalls and keeps the construction logic easy to read.
const { URL } = require('url');
function buildUrl(base, params) {
const url = new URL(base);
Object.entries(params).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
return url.toString();
}
const apiUrl = buildUrl('https://api.example.com/users', {
page: 1,
limit: 10,
sort: 'name'
});
console.log(apiUrl);
// "https://api.example.com/users?page=1&limit=10&sort=name"
Extracting information from request URLs
In a Node.js HTTP server, request URLs often arrive as relative paths. Passing them to the URL constructor with a base URL lets you parse pathnames, query parameters, and other components without writing your own parser, and the resulting object works naturally with Express-style routing logic.
const { URL } = require('url');
function parseRequestUrl(reqUrl, baseUrl = 'http://localhost:3000') {
const url = new URL(reqUrl, baseUrl);
return {
pathname: url.pathname,
params: Object.fromEntries(url.searchParams),
isJson: url.pathname.endsWith('.json') || url.searchParams.get('format') === 'json'
};
}
const result = parseRequestUrl('/api/users?page=2&active=true');
console.log(result);
// { pathname: '/api/users', params: { page: '2', active: 'true' }, isJson: false }
URL Validation
The most reliable way to check whether a string is a valid URL is to pass it to the URL constructor inside a try/catch block. The WHATWG parser validates the full structure—scheme, host, path, and query—and throws a TypeError for any input it cannot parse. This catches errors that a hand-written regex would miss.
const { URL } = require('url');
function isValidUrl(string) {
try {
new URL(string);
return true;
} catch (_) {
return false;
}
}
console.log(isValidUrl('https://example.com')); // true
console.log(isValidUrl('not-a-url')); // false
console.log(isValidUrl('ftp://files.example')); // true
File URL Handling (Node.js specific)
Node.js can convert between file:// URLs and file system paths. The URL class handles the platform-specific path separators and encoding automatically, which is especially useful when your code needs to work across Windows, macOS, and Linux without manual path manipulation.
const { URL } = require('url');
// Convert file path to file:// URL
const fileUrl = new URL('file:///Users/name/project/file.txt');
console.log(fileUrl.pathname);
// Convert file:// URL to path
const path = fileUrl.pathname;
console.log(path); // "/Users/name/project/file.txt" (platform-specific)
Modern API vs legacy API
The URL class (WHATWG URL Standard) is the right choice for new code. It has a consistent, well-specified interface, supports relative URL resolution via the optional base argument, and its searchParams property gives you a clean URLSearchParams API for reading and writing query strings. The legacy url.parse() function predates the WHATWG standard, returns a plain object instead of a class instance, and lacks searchParams support. It also has subtle differences in how it handles edge cases like empty hostnames and IPv6 literals. Prefer the URL class in all new code; use url.parse() only when maintaining existing code that depends on it.
URL validation
The most reliable way to check whether a string is a valid URL is to attempt construction with new URL() and catch the TypeError it throws on invalid input. This approach is intentional — the spec-compliant parser rejects strings that look valid but contain illegal characters or unsupported schemes, and it handles all the edge cases that a regex would miss.
searchParams and the search property
url.searchParams and url.search are linked: mutating searchParams (via .set(), .append(), .delete()) automatically updates url.search, and assigning a new string to url.search rebuilds searchParams. They are always in sync. Note that searchParams preserves insertion order and allows duplicate keys, while directly assigning url.search re-parses the string, which may reorder or deduplicate entries depending on the platform.
See Also
- node:http — HTTP server and client
- node:https — HTTPS server and client