Back to Blog
Node.jsURLParsingWeb

Node.js URL Module Guide

Master the Node.js URL module for parsing, constructing, and manipulating URLs.

B
Bootspring Team
Engineering
February 19, 2020
6 min read

The URL module provides utilities for URL parsing and manipulation. Here's how to use it.

URL Constructor#

1// Create URL from string 2const url = new URL('https://example.com:8080/path/page?name=value#section'); 3 4console.log(url.href); // Full URL string 5console.log(url.protocol); // 'https:' 6console.log(url.host); // 'example.com:8080' 7console.log(url.hostname); // 'example.com' 8console.log(url.port); // '8080' 9console.log(url.pathname); // '/path/page' 10console.log(url.search); // '?name=value' 11console.log(url.hash); // '#section' 12console.log(url.origin); // 'https://example.com:8080' 13 14// With base URL 15const relative = new URL('/api/users', 'https://example.com'); 16console.log(relative.href); // 'https://example.com/api/users' 17 18// Resolve relative paths 19const resolved = new URL('../images/photo.jpg', 'https://example.com/pages/about/'); 20console.log(resolved.href); // 'https://example.com/pages/images/photo.jpg'

Modifying URLs#

1const url = new URL('https://example.com/path'); 2 3// Modify properties 4url.pathname = '/new-path'; 5url.port = '3000'; 6url.hash = '#footer'; 7 8console.log(url.href); 9// 'https://example.com:3000/new-path#footer' 10 11// Protocol change 12url.protocol = 'http'; 13console.log(url.href); 14// 'http://example.com:3000/new-path#footer' 15 16// Auth (username/password) 17url.username = 'user'; 18url.password = 'pass'; 19console.log(url.href); 20// 'http://user:pass@example.com:3000/new-path#footer' 21 22// Clear port 23url.port = ''; 24console.log(url.host); // 'example.com'

URLSearchParams#

1// From URL 2const url = new URL('https://example.com?name=alice&age=30'); 3const params = url.searchParams; 4 5// Get values 6console.log(params.get('name')); // 'alice' 7console.log(params.get('age')); // '30' 8console.log(params.get('city')); // null 9 10// Check existence 11console.log(params.has('name')); // true 12console.log(params.has('city')); // false 13 14// Get all values (for repeated params) 15const url2 = new URL('https://example.com?tag=js&tag=css&tag=html'); 16console.log(url2.searchParams.getAll('tag')); 17// ['js', 'css', 'html'] 18 19// Standalone URLSearchParams 20const params2 = new URLSearchParams('a=1&b=2'); 21const params3 = new URLSearchParams({ a: '1', b: '2' }); 22const params4 = new URLSearchParams([['a', '1'], ['b', '2']]);

Manipulating Query Parameters#

1const params = new URLSearchParams(); 2 3// Add parameters 4params.set('name', 'alice'); 5params.set('age', '30'); 6params.append('hobby', 'reading'); 7params.append('hobby', 'coding'); 8 9console.log(params.toString()); 10// 'name=alice&age=30&hobby=reading&hobby=coding' 11 12// Delete parameter 13params.delete('age'); 14 15// Sort alphabetically 16params.sort(); 17console.log(params.toString()); 18// 'hobby=reading&hobby=coding&name=alice' 19 20// Iterate 21for (const [key, value] of params) { 22 console.log(`${key}: ${value}`); 23} 24 25// Convert to object 26const obj = Object.fromEntries(params); 27// Note: loses duplicate keys 28 29// Get all entries 30const entries = [...params.entries()]; 31// [['hobby', 'reading'], ['hobby', 'coding'], ['name', 'alice']]

Building URLs#

1// Build URL programmatically 2function buildApiUrl(endpoint, params = {}) { 3 const url = new URL(endpoint, 'https://api.example.com'); 4 5 Object.entries(params).forEach(([key, value]) => { 6 if (value !== undefined && value !== null) { 7 url.searchParams.set(key, value); 8 } 9 }); 10 11 return url.toString(); 12} 13 14const apiUrl = buildApiUrl('/users', { 15 page: 1, 16 limit: 10, 17 sort: 'name', 18}); 19// 'https://api.example.com/users?page=1&limit=10&sort=name' 20 21// URL builder class 22class URLBuilder { 23 constructor(base) { 24 this.url = new URL(base); 25 } 26 27 path(segment) { 28 this.url.pathname += segment.startsWith('/') ? segment : `/${segment}`; 29 return this; 30 } 31 32 query(params) { 33 Object.entries(params).forEach(([key, value]) => { 34 this.url.searchParams.set(key, value); 35 }); 36 return this; 37 } 38 39 hash(fragment) { 40 this.url.hash = fragment; 41 return this; 42 } 43 44 toString() { 45 return this.url.href; 46 } 47} 48 49const url = new URLBuilder('https://example.com') 50 .path('/api') 51 .path('/users') 52 .query({ page: 1, limit: 10 }) 53 .hash('results') 54 .toString();

URL Validation#

1// Check if valid URL 2function isValidUrl(string) { 3 try { 4 new URL(string); 5 return true; 6 } catch { 7 return false; 8 } 9} 10 11console.log(isValidUrl('https://example.com')); // true 12console.log(isValidUrl('not-a-url')); // false 13 14// Validate specific protocols 15function isValidHttpUrl(string) { 16 try { 17 const url = new URL(string); 18 return url.protocol === 'http:' || url.protocol === 'https:'; 19 } catch { 20 return false; 21 } 22} 23 24// Extract and validate 25function parseUrl(urlString) { 26 try { 27 const url = new URL(urlString); 28 return { 29 valid: true, 30 protocol: url.protocol, 31 hostname: url.hostname, 32 pathname: url.pathname, 33 params: Object.fromEntries(url.searchParams), 34 }; 35 } catch (error) { 36 return { 37 valid: false, 38 error: error.message, 39 }; 40 } 41}

URL Encoding#

1// encodeURIComponent - for values 2const value = 'hello world & more'; 3const encoded = encodeURIComponent(value); 4// 'hello%20world%20%26%20more' 5 6// decodeURIComponent - decode values 7const decoded = decodeURIComponent(encoded); 8// 'hello world & more' 9 10// encodeURI - for full URLs (preserves special chars) 11const urlStr = 'https://example.com/path?name=hello world'; 12const encodedUrl = encodeURI(urlStr); 13// 'https://example.com/path?name=hello%20world' 14 15// URLSearchParams auto-encodes 16const params = new URLSearchParams(); 17params.set('message', 'Hello & Goodbye'); 18console.log(params.toString()); 19// 'message=Hello+%26+Goodbye' 20 21// File URLs 22const filePath = '/Users/name/Documents/file name.txt'; 23const fileUrl = new URL(`file://${filePath}`); 24console.log(fileUrl.href); 25// Encoded properly

Practical Patterns#

1// Parse and modify existing URL 2function addQueryParam(urlString, key, value) { 3 const url = new URL(urlString); 4 url.searchParams.set(key, value); 5 return url.toString(); 6} 7 8// Remove query parameters 9function removeQueryParams(urlString, ...keys) { 10 const url = new URL(urlString); 11 keys.forEach(key => url.searchParams.delete(key)); 12 return url.toString(); 13} 14 15// Get clean URL (no query/hash) 16function getCleanUrl(urlString) { 17 const url = new URL(urlString); 18 return `${url.origin}${url.pathname}`; 19} 20 21// Compare URLs ignoring order of params 22function urlsEqual(url1, url2) { 23 const a = new URL(url1); 24 const b = new URL(url2); 25 26 a.searchParams.sort(); 27 b.searchParams.sort(); 28 29 return a.href === b.href; 30} 31 32// Merge query parameters 33function mergeQueryParams(urlString, newParams) { 34 const url = new URL(urlString); 35 36 Object.entries(newParams).forEach(([key, value]) => { 37 if (value === null) { 38 url.searchParams.delete(key); 39 } else { 40 url.searchParams.set(key, value); 41 } 42 }); 43 44 return url.toString(); 45}

Common Use Cases#

1// API request builder 2class ApiClient { 3 constructor(baseUrl) { 4 this.baseUrl = new URL(baseUrl); 5 } 6 7 buildUrl(path, params = {}) { 8 const url = new URL(path, this.baseUrl); 9 10 Object.entries(params).forEach(([key, value]) => { 11 if (Array.isArray(value)) { 12 value.forEach(v => url.searchParams.append(key, v)); 13 } else if (value !== undefined) { 14 url.searchParams.set(key, String(value)); 15 } 16 }); 17 18 return url.toString(); 19 } 20 21 async get(path, params) { 22 const url = this.buildUrl(path, params); 23 return fetch(url); 24 } 25} 26 27// Pagination URLs 28function paginationUrls(currentUrl, currentPage, totalPages) { 29 const url = new URL(currentUrl); 30 31 return { 32 first: (() => { 33 url.searchParams.set('page', '1'); 34 return url.toString(); 35 })(), 36 prev: currentPage > 1 ? (() => { 37 url.searchParams.set('page', String(currentPage - 1)); 38 return url.toString(); 39 })() : null, 40 next: currentPage < totalPages ? (() => { 41 url.searchParams.set('page', String(currentPage + 1)); 42 return url.toString(); 43 })() : null, 44 last: (() => { 45 url.searchParams.set('page', String(totalPages)); 46 return url.toString(); 47 })(), 48 }; 49}

Best Practices#

Parsing: ✓ Use URL constructor for validation ✓ Use URLSearchParams for queries ✓ Handle parsing errors gracefully ✓ Validate protocols when needed Building: ✓ Use URL for constructing URLs ✓ Let URLSearchParams handle encoding ✓ Build from trusted base URLs ✓ Sanitize user input Encoding: ✓ Use encodeURIComponent for values ✓ Let URL handle most encoding ✓ Be careful with double-encoding ✓ Test with special characters Avoid: ✗ String concatenation for URLs ✗ Manual encoding when not needed ✗ Assuming URL structure ✗ Ignoring edge cases

Conclusion#

The URL module provides robust URL parsing and manipulation. Use the URL constructor for validation and modification, URLSearchParams for query string handling, and proper encoding functions for safety. Build URLs programmatically rather than concatenating strings.

Share this article

Help spread the word about Bootspring