whatwg-url vs uri-js vs url-parse vs query-string vs uri-template
URL Parsing and Manipulation Libraries in JavaScript
whatwg-urluri-jsurl-parsequery-stringuri-templateSimilar Packages:

URL Parsing and Manipulation Libraries in JavaScript

query-string, uri-js, uri-template, url-parse, and whatwg-url are JavaScript libraries designed to handle various aspects of URI (Uniform Resource Identifier) manipulation, parsing, and construction. query-string specializes in encoding and decoding URL query parameters with support for arrays and objects. uri-js provides comprehensive URI parsing, validation, and resolution according to RFC 3986 and related standards. uri-template implements RFC 6570 for expanding URI templates with dynamic values. url-parse offers a lightweight, cross-environment URL parser that works consistently in both browsers and Node.js. whatwg-url is a spec-compliant implementation of the WHATWG URL Standard, providing URL and URLSearchParams APIs that match modern browser behavior, even in older JavaScript environments.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
whatwg-url180,454,573420106 kB14 days agoMIT
uri-js130,357,159317-305 years agoBSD-2-Clause
url-parse37,728,2711,03563 kB16-MIT
query-string21,242,7166,90459.1 kB25 days agoMIT
uri-template510,81744-25 years agoMIT

Parsing and Manipulating URLs in JavaScript: A Deep Dive into query-string, uri-js, uri-template, url-parse, and whatwg-url

When building modern web applications — especially those that interact with APIs, handle routing, or manage client-side state via the URL — you’ll inevitably need to parse, construct, or manipulate URIs. While browsers provide native APIs like URL and URLSearchParams, they don’t cover every use case, particularly around templating, full RFC compliance, or lightweight parsing without side effects. That’s where specialized npm packages come in.

Let’s compare five widely used libraries: query-string, uri-js, uri-template, url-parse, and whatwg-url. Each serves a distinct purpose, and choosing the right one depends on your specific needs around standards compliance, feature scope, and browser compatibility.

🔍 Core Purpose: What Problem Does Each Solve?

query-string

Focused exclusively on parsing and stringifying query strings (the part after ? in a URL). It supports array/object serialization, custom delimiters, and decoding strategies. It does not parse full URLs — just the search component.

import queryString from 'query-string';

const parsed = queryString.parse('foo=bar&baz=qux');
// { foo: 'bar', baz: 'qux' }

const str = queryString.stringify({ x: [1, 2], y: 'hello' });
// 'x=1&x=2&y=hello'

uri-js

A full-featured URI parser and validator based strictly on RFC 3986. It can parse, resolve, normalize, and validate any URI component (scheme, authority, path, query, fragment). It also supports IRI (Internationalized Resource Identifiers) and URNs.

import * as URI from 'uri-js';

const parts = URI.parse('https://example.com/path?foo=bar#section');
// { scheme: 'https', host: 'example.com', path: '/path', query: 'foo=bar', fragment: 'section' }

URI.resolve('https://a.com/base/', '../other');
// 'https://a.com/other'

uri-template

Specializes in expanding URI templates as defined by RFC 6570. You define a template like /users/{id}/posts{?page,size} and inject values to produce a concrete URL.

import UriTemplate from 'uri-template';

const template = UriTemplate.parse('/api/users/{userId}{?active,role}');
const url = template.expand({ userId: 123, active: true, role: 'admin' });
// '/api/users/123?active=true&role=admin'

url-parse

A lightweight, cross-environment URL parser that works consistently in both Node.js and browsers. It parses full URLs into components and offers utilities for relative URL resolution and origin comparison.

import Url from 'url-parse';

const url = new Url('https://user:pass@sub.example.com:8080/path?query=1#frag');
console.log(url.hostname); // 'sub.example.com'
console.log(url.port);     // '8080'

// Resolve relative URL
const base = new Url('https://example.com/base/');
const resolved = base.resolve('../other');
// 'https://example.com/other'

whatwg-url

A spec-compliant implementation of the WHATWG URL Standard, which is the same standard used by modern browsers. It provides URL and URLSearchParams classes that behave identically to their browser counterparts, even in older Node.js versions.

import { URL, URLSearchParams } from 'whatwg-url';

const url = new URL('https://example.com/path?foo=bar');
url.searchParams.append('baz', 'qux');
console.log(url.toString());
// 'https://example.com/path?foo=bar&baz=qux'

// Works exactly like browser's URL

🧪 Standards Compliance: Which Spec Do They Follow?

This is a critical differentiator:

  • whatwg-url implements the WHATWG URL Standard — the living standard used by all modern browsers. If you want behavior that matches new URL() in Chrome or Firefox, this is your choice.
  • uri-js follows RFC 3986 (and related RFCs like 6570 for templating via an add-on). This is more academic and strict, supporting edge cases like IPv6 literals, percent-encoding rules, and URN schemes.
  • url-parse aims for practical compatibility, not strict RFC adherence. It handles real-world URLs well but may diverge from formal specs in ambiguous cases.
  • query-string and uri-template each implement specific sub-standards: query-string uses common web conventions (similar to application/x-www-form-urlencoded), while uri-template strictly follows RFC 6570.

⚠️ Note: The WHATWG standard and RFC 3986 are not identical. For example, WHATWG normalizes hosts to lowercase and enforces stricter port parsing. In most web apps, WHATWG behavior is preferred because it matches the browser.

🛠️ Feature Comparison: Parsing, Building, and Beyond

Full URL Parsing

PackageParses full URL?Returns structured object?Resolves relative URLs?
query-string❌ No❌ Only query string
uri-js✅ Yes✅ Detailed parts✅ (resolve)
uri-template❌ No❌ Template only
url-parse✅ Yes✅ Simple object✅ (resolve method)
whatwg-url✅ YesURL instance❌ (use .href with base)

Example: resolving a relative path

// uri-js
URI.resolve('https://a.com/base/', '../other'); // 'https://a.com/other'

// url-parse
new Url('https://a.com/base/').resolve('../other'); // 'https://a.com/other'

// whatwg-url (requires base URL as second arg)
new URL('../other', 'https://a.com/base/').href; // 'https://a.com/other'

Query String Handling

Only query-string and whatwg-url (via URLSearchParams) offer rich query manipulation:

// query-string
queryString.parseUrl('https://x.com/?a=1&a=2').query;
// { a: ['1', '2'] } — arrays supported by default

// whatwg-url
const params = new URLSearchParams('a=1&a=2');
params.getAll('a'); // ['1', '2']

However, query-string supports nested objects and custom array formats out of the box:

queryString.stringify({ filter: { type: 'user', active: true } }, { arrayFormat: 'bracket' });
// 'filter[type]=user&filter[active]=true'

URLSearchParams does not support nested structures — it only handles flat key-value pairs.

URI Templating

Only uri-template handles RFC 6570 templates:

// uri-template
UriTemplate.parse('/search{?q,lang}').expand({ q: 'js', lang: 'en' });
// '/search?q=js&lang=en'

// Other packages cannot do this natively

If you’re consuming hypermedia APIs (like those using HAL or OpenAPI with templated links), this is essential.

🌐 Environment Support and Polyfill Strategy

  • whatwg-url is ideal when you need consistent URL behavior across Node.js versions, especially pre-v10 where native URL was incomplete. In modern environments (Node 14+, evergreen browsers), you might not need it — but it’s safe to use as a polyfill.
  • url-parse shines in isomorphic apps where you can’t rely on the global URL (e.g., old browsers or strict CSP environments). It’s dependency-free and tiny.
  • uri-js works everywhere but is heavier due to its comprehensive RFC support. Avoid if you only need basic parsing.
  • query-string is pure utility — no environment assumptions. Perfect for query manipulation regardless of platform.
  • uri-template is environment-agnostic and focused solely on templating.

🚫 Common Pitfalls and Misuses

  • Don’t use query-string to parse full URLs. It will treat the entire string as a query, leading to bugs:

    queryString.parse('https://example.com?foo=bar');
    // { 'https://example.com?foo': 'bar' } ← wrong!
    
  • Don’t expect whatwg-url to handle URI templates. It’s strictly for concrete URLs.

  • Avoid mixing uri-js and whatwg-url in the same codebase unless you understand their spec differences. They may produce different results for edge-case URLs.

  • url-parse does not auto-decode percent-encoded components like whatwg-url does. You may need to call decodeURIComponent manually on parts like pathname.

📊 When to Use Which?

Use CaseRecommended Package(s)
Parse or build query strings with arrays/objectsquery-string
Need exact browser-like URL behaviorwhatwg-url (or native URL)
Work with RFC 6570 URI templatesuri-template
Lightweight, consistent parsing in all JS envsurl-parse
Full RFC 3986 compliance (e.g., for tooling)uri-js
Validate or normalize complex URIs (IPv6, etc)uri-js

💡 Final Guidance

  • For most frontend apps, start with the native URL and URLSearchParams. Only reach for whatwg-url if you need to support older runtimes.
  • If you need advanced query string features (nested objects, array formats), query-string is unmatched.
  • If your API uses templated links (common in RESTful hypermedia), uri-template is the only correct choice.
  • Use url-parse when you can’t trust the environment’s URL implementation but don’t need full RFC rigor.
  • Reserve uri-js for tooling, validators, or systems requiring strict URI conformance — it’s overkill for typical app logic.

These libraries aren’t competitors — they solve different layers of the URI problem. The key is matching the tool to the task.

How to Choose: whatwg-url vs uri-js vs url-parse vs query-string vs uri-template

  • whatwg-url:

    Choose whatwg-url when you require exact parity with the browser’s native URL and URLSearchParams APIs in environments where they’re missing or incomplete (e.g., legacy Node.js). It’s the safest way to ensure your URL logic behaves identically across client and server. In modern runtimes, prefer the native APIs unless you need guaranteed consistency.

  • uri-js:

    Choose uri-js when you need strict compliance with RFC 3986 for URI parsing, validation, normalization, or resolution — such as in tooling, linters, or systems that must handle edge cases like IPv6 literals, internationalized domain names, or non-http schemes. It’s overkill for typical web app routing but invaluable when correctness per formal standards is non-negotiable.

  • url-parse:

    Choose url-parse when you need a lightweight, dependency-free URL parser that behaves consistently across all JavaScript environments (including older browsers and Node.js) without relying on global URL. It’s well-suited for isomorphic apps or libraries that must avoid native API inconsistencies, though it lacks advanced query handling or strict RFC compliance.

  • query-string:

    Choose query-string when your primary need is robust parsing and stringification of URL query strings, especially if you require support for nested objects, array formats (like bracket notation), or custom encoding/decoding strategies. It’s ideal for client-side state management via query parameters or API clients that serialize complex filters into URLs. Avoid it if you need to parse full URLs or handle URI templates.

  • uri-template:

    Choose uri-template exclusively when working with RFC 6570 URI templates, commonly found in hypermedia-driven APIs (e.g., HAL, OpenAPI). It allows you to safely expand templates like /users/{id}{?active,role} into concrete URLs. Don’t use it for general URL parsing or query string manipulation — it serves one narrow but critical purpose.

README for whatwg-url

whatwg-url

whatwg-url is a full implementation of the WHATWG URL Standard. It can be used standalone, but it also exposes a lot of the internal algorithms that are useful for integrating a URL parser into a project like jsdom.

Specification conformance

whatwg-url is currently up to date with the URL spec up to commit 3c83874 and the web platform tests up to commit 2a91c2e.

For file: URLs, whose origin is left unspecified, whatwg-url chooses to use a new opaque origin (which serializes to "null").

API

The URL and URLSearchParams classes

The main API is provided by the URL and URLSearchParams exports, which follows the spec's behavior in all ways (including e.g. USVString conversion). Most consumers of this library will want to use these.

Low-level URL Standard API

The following methods are exported for use by places like jsdom that need to implement things like HTMLHyperlinkElementUtils. They mostly operate on or return an "internal URL" or "URL record" type.

The stateOverride parameter is one of the following strings:

The URL record type has the following API:

These properties should be treated with care, as in general changing them will cause the URL record to be in an inconsistent state until the appropriate invocation of basicURLParse is used to fix it up. You can see examples of this in the URL Standard, where there are many step sequences like "4. Set context object’s url’s fragment to the empty string. 5. Basic URL parse input with context object’s url as url and fragment state as state override." In between those two steps, a URL record is in an unusable state.

The return value of "failure" in the spec is represented by null. That is, functions like parseURL and basicURLParse can return either a URL record or null.

whatwg-url/webidl2js-wrapper module

This module exports the URL and URLSearchParams interface wrappers API generated by webidl2js.

Development instructions

First, install Node.js. Then, fetch the dependencies of whatwg-url, by running from this directory:

npm install

To run tests:

npm test

To generate a coverage report:

npm run coverage

To build and run the live viewer:

npm run prepare
npm run build-live-viewer

Serve the contents of the live-viewer directory using any web server.

Supporting whatwg-url

The jsdom project (including whatwg-url) is a community-driven project maintained by a team of volunteers. You could support us by:

  • Getting professional support for whatwg-url as part of a Tidelift subscription. Tidelift helps making open source sustainable for us while giving teams assurances for maintenance, licensing, and security.
  • Contributing directly to the project.