The URL module provides utilities for URL parsing and manipulation using the WHATWG URL Standard.
URL Class#
1// Create URL object
2const myURL = new URL('https://user:pass@example.com:8080/path/name?query=value#hash');
3
4console.log(myURL.href); // Full URL
5console.log(myURL.protocol); // 'https:'
6console.log(myURL.username); // 'user'
7console.log(myURL.password); // 'pass'
8console.log(myURL.host); // 'example.com:8080'
9console.log(myURL.hostname); // 'example.com'
10console.log(myURL.port); // '8080'
11console.log(myURL.pathname); // '/path/name'
12console.log(myURL.search); // '?query=value'
13console.log(myURL.hash); // '#hash'
14console.log(myURL.origin); // 'https://example.com:8080'
15
16// Modify URL parts
17myURL.pathname = '/new/path';
18myURL.hash = 'section';
19console.log(myURL.href);
20// 'https://user:pass@example.com:8080/new/path?query=value#section'Relative URLs#
1// Resolve relative URL against base
2const base = new URL('https://example.com/path/page.html');
3const relative = new URL('../other/file.html', base);
4
5console.log(relative.href);
6// 'https://example.com/other/file.html'
7
8// Various relative paths
9new URL('/absolute', 'https://example.com/path/');
10// 'https://example.com/absolute'
11
12new URL('relative', 'https://example.com/path/');
13// 'https://example.com/path/relative'
14
15new URL('./same-level', 'https://example.com/path/');
16// 'https://example.com/path/same-level'
17
18new URL('../parent-level', 'https://example.com/path/sub/');
19// 'https://example.com/path/parent-level'
20
21// Protocol-relative
22new URL('//cdn.example.com/file.js', 'https://example.com');
23// 'https://cdn.example.com/file.js'URLSearchParams#
1// Parse query string
2const url = new URL('https://example.com?name=John&age=30&hobby=coding&hobby=reading');
3const params = url.searchParams;
4
5// Get values
6params.get('name'); // 'John'
7params.get('age'); // '30'
8params.get('hobby'); // 'coding' (first value)
9params.getAll('hobby'); // ['coding', 'reading']
10params.has('name'); // true
11
12// Iterate
13for (const [key, value] of params) {
14 console.log(`${key}: ${value}`);
15}
16
17params.forEach((value, key) => {
18 console.log(`${key}: ${value}`);
19});
20
21// Keys and values
22[...params.keys()]; // ['name', 'age', 'hobby', 'hobby']
23[...params.values()]; // ['John', '30', 'coding', 'reading']
24[...params.entries()]; // [['name', 'John'], ...]
25
26// Modify
27params.set('name', 'Jane'); // Replace value
28params.append('skill', 'js'); // Add new
29params.delete('age'); // Remove
30
31console.log(url.href);
32// 'https://example.com/?name=Jane&hobby=coding&hobby=reading&skill=js'Creating URLSearchParams#
1// From string
2const params1 = new URLSearchParams('name=John&age=30');
3
4// From object
5const params2 = new URLSearchParams({
6 name: 'John',
7 age: '30',
8 active: 'true'
9});
10
11// From array of pairs
12const params3 = new URLSearchParams([
13 ['name', 'John'],
14 ['hobby', 'coding'],
15 ['hobby', 'reading'] // Duplicate keys allowed
16]);
17
18// From another URLSearchParams
19const params4 = new URLSearchParams(params1);
20
21// Convert to string
22params2.toString(); // 'name=John&age=30&active=true'
23
24// Sort alphabetically
25params2.sort();
26params2.toString(); // 'active=true&age=30&name=John'URL Encoding#
1// URLSearchParams handles encoding
2const params = new URLSearchParams();
3params.set('query', 'hello world');
4params.set('special', 'a&b=c');
5
6params.toString();
7// 'query=hello+world&special=a%26b%3Dc'
8
9// Manual encoding
10encodeURIComponent('hello world'); // 'hello%20world'
11encodeURI('https://example.com/path with spaces');
12// 'https://example.com/path%20with%20spaces'
13
14// Decoding
15decodeURIComponent('hello%20world'); // 'hello world'
16decodeURI('https://example.com/path%20with%20spaces');
17// 'https://example.com/path with spaces'Building URLs#
1// Build URL programmatically
2function buildUrl(base, path, params = {}) {
3 const url = new URL(path, base);
4
5 Object.entries(params).forEach(([key, value]) => {
6 if (Array.isArray(value)) {
7 value.forEach(v => url.searchParams.append(key, v));
8 } else if (value !== undefined && value !== null) {
9 url.searchParams.set(key, String(value));
10 }
11 });
12
13 return url.href;
14}
15
16const apiUrl = buildUrl('https://api.example.com', '/users', {
17 page: 1,
18 limit: 10,
19 sort: 'name',
20 filter: ['active', 'verified']
21});
22
23// 'https://api.example.com/users?page=1&limit=10&sort=name&filter=active&filter=verified'
24
25// URL builder class
26class UrlBuilder {
27 constructor(base) {
28 this.url = new URL(base);
29 }
30
31 path(path) {
32 this.url.pathname = path;
33 return this;
34 }
35
36 query(key, value) {
37 this.url.searchParams.set(key, value);
38 return this;
39 }
40
41 queries(params) {
42 Object.entries(params).forEach(([k, v]) => {
43 this.url.searchParams.set(k, v);
44 });
45 return this;
46 }
47
48 hash(hash) {
49 this.url.hash = hash;
50 return this;
51 }
52
53 build() {
54 return this.url.href;
55 }
56}
57
58const url = new UrlBuilder('https://example.com')
59 .path('/api/users')
60 .queries({ page: '1', limit: '20' })
61 .hash('results')
62 .build();Validating URLs#
1// Check if string is valid URL
2function isValidUrl(string) {
3 try {
4 new URL(string);
5 return true;
6 } catch {
7 return false;
8 }
9}
10
11isValidUrl('https://example.com'); // true
12isValidUrl('not a url'); // false
13isValidUrl('example.com'); // false (no protocol)
14
15// Validate with constraints
16function isValidHttpUrl(string) {
17 try {
18 const url = new URL(string);
19 return url.protocol === 'http:' || url.protocol === 'https:';
20 } catch {
21 return false;
22 }
23}
24
25// Extract domain
26function getDomain(urlString) {
27 try {
28 const url = new URL(urlString);
29 return url.hostname;
30 } catch {
31 return null;
32 }
33}
34
35getDomain('https://www.example.com/path'); // 'www.example.com'URL Comparison#
1// URLs are normalized
2const url1 = new URL('HTTPS://Example.COM/path/');
3const url2 = new URL('https://example.com/path/');
4
5url1.href === url2.href; // true (both normalized)
6
7// Compare specific parts
8function isSameOrigin(url1, url2) {
9 const a = new URL(url1);
10 const b = new URL(url2);
11 return a.origin === b.origin;
12}
13
14isSameOrigin(
15 'https://example.com/path1',
16 'https://example.com/path2'
17); // true
18
19isSameOrigin(
20 'https://example.com',
21 'https://api.example.com'
22); // false (different subdomain)
23
24// Check if URL matches pattern
25function matchesPattern(url, pattern) {
26 const urlObj = new URL(url);
27 const patternObj = new URL(pattern);
28
29 return (
30 urlObj.hostname === patternObj.hostname &&
31 urlObj.pathname.startsWith(patternObj.pathname)
32 );
33}File URLs#
1import { fileURLToPath, pathToFileURL } from 'url';
2import { dirname } from 'path';
3
4// Convert file URL to path
5const filePath = fileURLToPath(import.meta.url);
6// /Users/user/project/file.js
7
8// Get directory name (ESM equivalent of __dirname)
9const __dirname = dirname(fileURLToPath(import.meta.url));
10
11// Convert path to file URL
12const url = pathToFileURL('/path/to/file.js');
13// file:///path/to/file.js
14
15// Works with import()
16const config = await import(pathToFileURL('./config.js'));Legacy URL Module#
1import { parse, format, resolve } from 'url';
2
3// Legacy parse (deprecated but still works)
4const parsed = parse('https://example.com/path?query=value', true);
5console.log(parsed.query); // { query: 'value' } as object
6
7// Legacy format
8const formatted = format({
9 protocol: 'https',
10 hostname: 'example.com',
11 pathname: '/path',
12 query: { key: 'value' }
13});
14// 'https://example.com/path?key=value'
15
16// Legacy resolve
17resolve('https://example.com/path/', '../other');
18// 'https://example.com/other'
19
20// Prefer WHATWG URL class for new codeCommon Patterns#
1// Extract pathname segments
2function getPathSegments(urlString) {
3 const url = new URL(urlString);
4 return url.pathname.split('/').filter(Boolean);
5}
6
7getPathSegments('https://example.com/api/v1/users');
8// ['api', 'v1', 'users']
9
10// Add/update single query parameter
11function setQueryParam(urlString, key, value) {
12 const url = new URL(urlString);
13 url.searchParams.set(key, value);
14 return url.href;
15}
16
17// Remove query parameter
18function removeQueryParam(urlString, key) {
19 const url = new URL(urlString);
20 url.searchParams.delete(key);
21 return url.href;
22}
23
24// Get clean URL (no query, no hash)
25function getCleanUrl(urlString) {
26 const url = new URL(urlString);
27 url.search = '';
28 url.hash = '';
29 return url.href;
30}
31
32// Parse hash parameters (for SPAs)
33function parseHashParams(urlString) {
34 const url = new URL(urlString);
35 const hashParams = new URLSearchParams(url.hash.slice(1));
36 return Object.fromEntries(hashParams);
37}
38
39parseHashParams('https://example.com#access_token=abc&expires_in=3600');
40// { access_token: 'abc', expires_in: '3600' }Best Practices#
URL Class:
✓ Use WHATWG URL class (new URL)
✓ Handle URL construction errors
✓ Use searchParams for query strings
✓ Normalize URLs for comparison
Security:
✓ Validate URLs before use
✓ Check protocol (http/https)
✓ Sanitize user-provided URLs
✓ Use URL encoding for parameters
Patterns:
✓ Create URL builders for complex URLs
✓ Use relative URLs when possible
✓ Extract common URL operations
✓ Handle edge cases
Avoid:
✗ String concatenation for URLs
✗ Manual query string building
✗ Forgetting to encode values
✗ Using deprecated url.parse
Conclusion#
The Node.js URL module provides robust URL parsing and manipulation following the WHATWG URL Standard. Use the URL class for parsing and constructing URLs, URLSearchParams for query string handling, and fileURLToPath/pathToFileURL for file system integration. Always validate URLs and use proper encoding. The modern URL class should be preferred over the legacy url.parse function.