How to Parse URLs in JavaScript: The URL API vs Manual Parsing

Published: (May 2, 2026 at 06:33 AM EDT)
3 min read
Source: Dev.to

Source: Dev.to

Using the URL class

const url = new URL('https://example.com:8080/path/page?q=hello+world&lang=en#section');

url.protocol; // "https:"
url.hostname; // "example.com"
url.port;     // "8080"
url.host;     // "example.com:8080"
url.pathname; // "/path/page"
url.search;   // "?q=hello+world&lang=en"
url.hash;     // "#section"
url.origin;   // "https://example.com:8080"
url.href;     // full URL string

The parser handles edge cases automatically. Standard ports are omitted from host:

new URL('http://example.com:80/').host; // "example.com"

Query parameters with URLSearchParams

Never split on & and = manually—values can contain encoded & and = characters. Use URLSearchParams instead:

const url = new URL('https://example.com?q=hello+world&tags=js&tags=css');
const params = url.searchParams;

params.get('q');        // "hello world" (decodes `+` as space)
params.getAll('tags'); // ["js", "css"]
params.has('tags');    // true

// Iterate all params
for (const [key, value] of params) {
  console.log(key, value);
}
// q hello world
// tags js
// tags css

Building a query string

const params = new URLSearchParams({
  q: 'hello world',
  sort: 'date',
  page: '1'
});
params.toString(); // "q=hello+world&sort=date&page=1"

Appending without replacing

params.append('tags', 'javascript');
params.append('tags', 'css');
params.toString(); // "q=hello+world&sort=date&page=1&tags=javascript&tags=css"

Modifying an existing URL

const url = new URL('https://example.com?page=1&sort=date');

url.searchParams.set('page', '2');   // update
url.searchParams.delete('sort');    // remove
url.searchParams.append('filter', 'active'); // add

url.href; // "https://example.com/?page=2&filter=active"

Resolving relative URLs

new URL('/about', 'https://example.com').href;
// "https://example.com/about"

new URL('../images/photo.jpg', 'https://example.com/blog/post/').href;
// "https://example.com/blog/images/photo.jpg"

new URL('?page=2', 'https://example.com/articles').href;
// "https://example.com/articles?page=2"

This is the correct way to resolve relative links when scraping or building crawlers.

Percent‑encoding automatically

const url = new URL('https://example.com/search');
url.searchParams.set('q', 'café & creme brûlée');
url.href;
// "https://example.com/search?q=caf%C3%A9+%26+creme+br%C3%BBl%C3%A9e"

Manual encoding/decoding

// Encode a component value (e.g., query parameter value)
encodeURIComponent('hello world & more');
// "hello%20world%20%26%20more"

// Encode a full URL (preserves :, /, ?, =, &, #, @)
encodeURI('https://example.com/path?q=hello world');
// "https://example.com/path?q=hello%20world"

// Decode
decodeURIComponent('hello%20world');
// "hello world"

Validating URLs

function isValidUrl(string) {
  try {
    new URL(string);
    return true;
  } catch {
    return false;
  }
}

isValidUrl('https://example.com'); // true
isValidUrl('not a url');           // false
isValidUrl('//example.com');       // true (protocol‑relative)

If you need to require a specific protocol:

function isHttpUrl(string) {
  try {
    const url = new URL(string);
    return url.protocol === 'http:' || url.protocol === 'https:';
  } catch {
    return false;
  }
}

Hostname vs. host

new URL('https://sub.example.co.uk/path').hostname;
// "sub.example.co.uk"

new URL('https://example.com:443/path').host;     // "example.com:443"
new URL('https://example.com:443/path').hostname; // "example.com"

hostname strips the port; host includes it.

Node.js compatibility

The URL class is globally available in Node.js since v10. For older versions:

const { URL, URLSearchParams } = require('url');

It is also available in Web Workers and Service Workers in the browser.

Legacy <a> element trick (browser only)

Before the URL API, developers used a DOM <a> element to parse URLs:

const a = document.createElement('a');
a.href = 'https://example.com/path';
a.hostname; // "example.com"

This approach works only in the browser, can behave inconsistently across browsers for edge cases, and does not support URLSearchParams. The modern URL API should be preferred.

Conclusion

The URL API, together with URLSearchParams, eliminates a whole category of bugs related to query‑string handling and edge‑case URL parsing. If you’re still manually splitting on ? and &, switch to the API—you’ll wonder how you ever parsed URLs without it.

0 views
Back to Blog

Related posts

Read more »

Making my own framework. Any tips?

!Cover image for Making my own framework. Any tips?https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fde...