devnotes.

Working with URLs in Node.js

You've already seen URL and URLSearchParams used in passing on the Query String page. This page looks at the URL module more completely — the pieces a URL breaks into, and how Node.js lets you read and build them.

Anatomy of a URL

https://user:pass@shop.example.com:8080/products/shoes?color=black&size=42#reviews
const { URL } = require('url');
const myUrl = new URL('https://user:pass@shop.example.com:8080/products/shoes?color=black&size=42#reviews');

console.log(myUrl.protocol);   // 'https:'
console.log(myUrl.username);   // 'user'
console.log(myUrl.password);   // 'pass'
console.log(myUrl.hostname);   // 'shop.example.com'
console.log(myUrl.port);       // '8080'
console.log(myUrl.pathname);   // '/products/shoes'
console.log(myUrl.search);     // '?color=black&size=42'
console.log(myUrl.hash);       // '#reviews'
console.log(myUrl.origin);     // 'https://shop.example.com:8080'
console.log(myUrl.href);       // the entire URL as a string

Each piece is its own property — no manual string-splitting or regular expressions needed to pull a URL apart.

Building a URL from pieces, rather than parsing one

const apiUrl = new URL('https://api.example.com');
apiUrl.pathname = '/v1/products';
apiUrl.searchParams.set('category', 'electronics');
apiUrl.searchParams.set('limit', '20');

console.log(apiUrl.href);
// https://api.example.com/v1/products?category=electronics&limit=20

Assigning to properties like pathname and using .searchParams.set() builds the URL incrementally and correctly, handling any characters that need escaping automatically.

Resolving a relative URL against a base

const base = 'https://shop.example.com/products/';
console.log(new URL('shoes', base).href);        // 'https://shop.example.com/products/shoes'
console.log(new URL('/cart', base).href);         // 'https://shop.example.com/cart'
console.log(new URL('../about', base).href);      // 'https://shop.example.com/about'

This mirrors exactly how a browser resolves a relative link (href="shoes") against the page it's on — useful when your server-side code needs the same resolution logic.

Reading and modifying query parameters together

const pageUrl = new URL('https://shop.example.com/search?q=laptop&page=1');

pageUrl.searchParams.set('page', '2');       // update an existing parameter
pageUrl.searchParams.append('sort', 'price'); // add a new one
pageUrl.searchParams.delete('q');             // remove one entirely

console.log(pageUrl.href);
// https://shop.example.com/search?page=2&sort=price

Where this shows up in practice

  • Reading the path and query string of an incoming server request.
  • Building outgoing API request URLs dynamically, with parameters computed at runtime.
  • Validating that a URL a user submitted is actually well-formed, by catching the error new URL() throws on invalid input:
function isValidUrl(str) {
  try {
    new URL(str);
    return true;
  } catch {
    return false;
  }
}

console.log(isValidUrl('https://example.com')); // true
console.log(isValidUrl('not a url'));             // false
Working with URLs in Node.js | DevNotes