query-string vs uri-js vs url-join vs url-parse vs url-template
URL Manipulation Libraries
query-stringuri-jsurl-joinurl-parseurl-templateSimilar Packages:

URL Manipulation Libraries

URL manipulation libraries are essential tools in web development that help developers parse, construct, and manipulate URLs effectively. They provide functionalities to handle query strings, manage URL components, and facilitate the creation of URLs in a structured manner. These libraries simplify the process of working with URLs, making it easier to build web applications that require dynamic routing, API calls, and navigation.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
query-string06,90557.7 kB26 months agoMIT
uri-js0318-305 years agoBSD-2-Clause
url-join03654.74 kB6-MIT
url-parse01,03963 kB14-MIT
url-template01947.99 kB12 years agoBSD-3-Clause

Feature Comparison: query-string vs uri-js vs url-join vs url-parse vs url-template

Parsing Capabilities

  • query-string:

    query-string excels at parsing and stringifying query strings, allowing developers to easily convert query parameters into JavaScript objects and vice versa. It handles encoding and decoding seamlessly, making it ideal for simple query manipulation.

  • uri-js:

    uri-js provides extensive parsing capabilities for URIs, supporting various schemes and components. It can parse complex URIs into their respective parts, such as protocol, host, path, and query, making it suitable for applications that require detailed URI handling.

  • url-join:

    url-join does not focus on parsing but rather on safely joining URL segments. It ensures that slashes are correctly placed between segments, preventing malformed URLs, which is crucial for dynamic URL construction.

  • url-parse:

    url-parse offers comprehensive parsing of URLs, breaking them down into components like protocol, hostname, port, pathname, search, and hash. This allows developers to easily access and manipulate specific parts of a URL as needed.

  • url-template:

    url-template allows for parsing of URL templates, enabling developers to define patterns with placeholders that can be replaced with actual values. This is particularly useful for generating URLs dynamically based on variable parameters.

Usage Scenario

  • query-string:

    query-string is best used in scenarios where you need to handle query parameters in web applications, such as extracting search filters from a URL or constructing query strings for API requests.

  • uri-js:

    uri-js is ideal for applications that need to validate, parse, and manipulate URIs across different schemes, such as web applications that interact with various APIs or services requiring strict URI compliance.

  • url-join:

    url-join is perfect for constructing URLs from multiple segments, such as building API endpoints or navigating between different routes in a web application without worrying about slashes.

  • url-parse:

    url-parse is useful in scenarios where you need to analyze or manipulate URLs, such as extracting parameters from a URL for routing or logging purposes in web applications.

  • url-template:

    url-template is suited for RESTful API interactions where URLs need to be dynamically generated based on user input or application state, allowing for flexible and reusable URL patterns.

Complexity and Size

  • query-string:

    query-string is lightweight and straightforward, making it easy to integrate into projects without adding significant overhead. Its simplicity is a key advantage for projects that require minimal dependencies.

  • uri-js:

    uri-js is more complex and feature-rich, which may introduce additional overhead. However, its comprehensive capabilities justify its size for applications that require extensive URI manipulation.

  • url-join:

    url-join is extremely lightweight and focused solely on URL joining, making it an efficient choice for projects that need a simple utility without unnecessary features.

  • url-parse:

    url-parse is a bit larger due to its robust parsing capabilities, but it is still manageable for most applications. Its detailed parsing features make it worth the size for applications requiring in-depth URL analysis.

  • url-template:

    url-template is relatively lightweight, but its functionality for handling templates adds some complexity. It is best used in scenarios where dynamic URL generation is essential.

Community and Support

  • query-string:

    query-string has a strong community and is widely used, ensuring good support and documentation. Its popularity makes it a reliable choice for handling query strings in JavaScript applications.

  • uri-js:

    uri-js is well-documented and has a dedicated user base, providing adequate support for developers needing to work with URIs. Its adherence to standards enhances its credibility.

  • url-join:

    url-join is simple and has a smaller community, but its straightforward functionality means that it is easy to use without extensive support needs.

  • url-parse:

    url-parse has a large user base and is frequently updated, providing robust community support and documentation, making it a reliable choice for URL parsing.

  • url-template:

    url-template has a smaller community but is well-documented, making it accessible for developers who need to implement URL templates in their applications.

Extensibility

  • query-string:

    query-string is designed for specific use cases and does not offer extensive extensibility options, making it straightforward but limited in customization.

  • uri-js:

    uri-js provides a flexible API that allows for extensions and custom implementations, making it suitable for advanced users who need to tailor its functionality to specific requirements.

  • url-join:

    url-join is not designed for extensibility, as it focuses solely on joining URLs. Its simplicity is both a strength and a limitation for developers looking for customizable solutions.

  • url-parse:

    url-parse offers some extensibility options, allowing developers to create custom parsing logic if needed. This makes it adaptable for various use cases beyond standard URL parsing.

  • url-template:

    url-template allows for some level of extensibility in defining templates, enabling developers to create reusable patterns for dynamic URL generation.

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

  • query-string:

    Choose query-string if you need a lightweight solution specifically for parsing and stringifying query strings. It's ideal for simple use cases where you want to handle URL parameters without additional overhead.

  • uri-js:

    Select uri-js when you require comprehensive support for URI parsing and manipulation, including handling of various URI schemes and components. It's suitable for applications that need to work with complex URIs and require strict compliance with URI standards.

  • url-join:

    Opt for url-join if your primary goal is to concatenate URL segments safely. This package is perfect for building URLs dynamically from multiple parts, ensuring that slashes are handled correctly without manual intervention.

  • url-parse:

    Use url-parse if you need a robust library for parsing URLs into their components. It provides a straightforward API for accessing different parts of a URL, making it useful for applications that require detailed URL analysis and manipulation.

  • url-template:

    Choose url-template when you need to work with URL templates that can be expanded with dynamic parameters. This is particularly useful for RESTful APIs where URLs may change based on variable inputs.

README for query-string

query-string

Parse and stringify URL query strings

Install

npm install query-string

[!WARNING] Remember the hyphen! Do not install the deprecated querystring package!

For browser usage, this package targets the latest version of Chrome, Firefox, and Safari.

Usage

import queryString from 'query-string';

console.log(location.search);
//=> '?foo=bar'

const parsed = queryString.parse(location.search);
console.log(parsed);
//=> {foo: 'bar'}

console.log(location.hash);
//=> '#token=bada55cafe'

const parsedHash = queryString.parse(location.hash);
console.log(parsedHash);
//=> {token: 'bada55cafe'}

parsed.foo = 'unicorn';
parsed.ilike = 'pizza';

const stringified = queryString.stringify(parsed);
//=> 'foo=unicorn&ilike=pizza'

location.search = stringified;
// note that `location.search` automatically prepends a question mark
console.log(location.search);
//=> '?foo=unicorn&ilike=pizza'

API

.parse(string, options?)

Parse a query string into an object. Leading ? or # are ignored, so you can pass location.search or location.hash directly.

The returned object is created with Object.create(null) and thus does not have a prototype.

queryString.parse('?foo=bar');
//=> {foo: 'bar'}

queryString.parse('#token=secret&name=jhon');
//=> {token: 'secret', name: 'jhon'}

options

Type: object

decode

Type: boolean
Default: true

Decode the keys and values. URL components are decoded with decode-uri-component.

arrayFormat

Type: string
Default: 'none'

  • 'bracket': Parse arrays with bracket representation:
import queryString from 'query-string';

queryString.parse('foo[]=1&foo[]=2&foo[]=3', {arrayFormat: 'bracket'});
//=> {foo: ['1', '2', '3']}
  • 'index': Parse arrays with index representation:
import queryString from 'query-string';

queryString.parse('foo[0]=1&foo[1]=2&foo[3]=3', {arrayFormat: 'index'});
//=> {foo: ['1', '2', '3']}
  • 'comma': Parse arrays with elements separated by comma:
import queryString from 'query-string';

queryString.parse('foo=1,2,3', {arrayFormat: 'comma'});
//=> {foo: ['1', '2', '3']}
  • 'separator': Parse arrays with elements separated by a custom character:
import queryString from 'query-string';

queryString.parse('foo=1|2|3', {arrayFormat: 'separator', arrayFormatSeparator: '|'});
//=> {foo: ['1', '2', '3']}
  • 'bracket-separator': Parse arrays (that are explicitly marked with brackets) with elements separated by a custom character:
import queryString from 'query-string';

queryString.parse('foo[]', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> {foo: []}

queryString.parse('foo[]=', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> {foo: ['']}

queryString.parse('foo[]=1', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> {foo: ['1']}

queryString.parse('foo[]=1|2|3', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> {foo: ['1', '2', '3']}

queryString.parse('foo[]=1||3|||6', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> {foo: ['1', '', 3, '', '', '6']}

queryString.parse('foo[]=1|2|3&bar=fluffy&baz[]=4', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> {foo: ['1', '2', '3'], bar: 'fluffy', baz:['4']}
  • 'colon-list-separator': Parse arrays with parameter names that are explicitly marked with :list:
import queryString from 'query-string';

queryString.parse('foo:list=one&foo:list=two', {arrayFormat: 'colon-list-separator'});
//=> {foo: ['one', 'two']}
  • 'none': Parse arrays with elements using duplicate keys:
import queryString from 'query-string';

queryString.parse('foo=1&foo=2&foo=3');
//=> {foo: ['1', '2', '3']}
arrayFormatSeparator

Type: string
Default: ','

The character used to separate array elements when using {arrayFormat: 'separator'}.

sort

Type: Function | boolean
Default: true

Supports both Function as a custom sorting function or false to disable sorting.

parseNumbers

Type: boolean
Default: false

import queryString from 'query-string';

queryString.parse('foo=1', {parseNumbers: true});
//=> {foo: 1}

Parse the value as a number type instead of string type if it's a number.

parseBooleans

Type: boolean
Default: false

import queryString from 'query-string';

queryString.parse('foo=true', {parseBooleans: true});
//=> {foo: true}

Parse the value as a boolean type instead of string type if it's a boolean.

types

Type: object
Default: {}

Specifies a schema for parsing query values with explicit type declarations. When defined, the types provided here take precedence over general parsing options such as parseNumbers, parseBooleans, and arrayFormat.

Use this option to explicitly define the type of a specific parameter—particularly useful in cases where the type might otherwise be ambiguous (e.g., phone numbers or IDs).

You can also provide a custom function to transform the value. The function will receive the raw string and should return the desired parsed result. When used with array formats (like comma, separator, bracket, etc.), the function is applied to each array element individually.

Supported Types:

  • 'boolean': Parse flagged as a boolean (overriding the parseBooleans option):
queryString.parse('?isAdmin=true&flagged=true&isOkay=0', {
		parseBooleans: false,
		types: {
				flagged: 'boolean',
				isOkay: 'boolean',
		},
});
//=> {isAdmin: 'true', flagged: true, isOkay: false}

Note: The 'boolean' type also converts '0' and '1' to booleans, and treats valueless keys (e.g. ?flag) as true.

  • 'string': Parse phoneNumber as a string (overriding the parseNumbers option):
import queryString from 'query-string';

queryString.parse('?phoneNumber=%2B380951234567&id=1', {
	parseNumbers: true,
	types: {
		phoneNumber: 'string',
	}
});
//=> {phoneNumber: '+380951234567', id: 1}
  • 'number': Parse age as a number (even when parseNumbers is false):
import queryString from 'query-string';

queryString.parse('?age=20&id=01234&zipcode=90210', {
	types: {
		age: 'number',
	}
});
//=> {age: 20, id: '01234', zipcode: '90210'}
  • 'string[]': Parse items as an array of strings (overriding the parseNumbers option):
import queryString from 'query-string';

queryString.parse('?age=20&items=1%2C2%2C3', {
	parseNumbers: true,
	types: {
		items: 'string[]',
	}
});
//=> {age: 20, items: ['1', '2', '3']}
  • 'number[]': Parse items as an array of numbers (even when parseNumbers is false):
import queryString from 'query-string';

queryString.parse('?age=20&items=1%2C2%2C3', {
	types: {
		items: 'number[]',
	}
});
//=> {age: '20', items: [1, 2, 3]}
  • 'Function': Provide a custom function as the parameter type. The parameter's value will equal the function's return value. When used with array formats (like comma, separator, bracket, etc.), the function is applied to each array element individually.
import queryString from 'query-string';

queryString.parse('?age=20&id=01234&zipcode=90210', {
	types: {
		age: value => value * 2,
	}
});
//=> {age: 40, id: '01234', zipcode: '90210'}

// With arrays, the function is applied to each element
queryString.parse('?scores=10,20,30', {
	arrayFormat: 'comma',
	types: {
		scores: value => Number(value) * 2,
	}
});
//=> {scores: [20, 40, 60]}

NOTE: Array types (string[], number[]) are ignored if arrayFormat is set to 'none'.

queryString.parse('ids=001%2C002%2C003&foods=apple%2Corange%2Cmango', {
	arrayFormat: 'none',
	types: {
		ids: 'number[]',
		foods: 'string[]',
	},
}
//=> {ids:'001,002,003', foods:'apple,orange,mango'}
Function
import queryString from 'query-string';

queryString.parse('?age=20&id=01234&zipcode=90210', {
	types: {
		age: value => value * 2,
	}
});
//=> {age: 40, id: '01234', zipcode: '90210'}

Parse the value as a boolean type instead of string type if it's a boolean.

.stringify(object, options?)

Stringify an object into a query string and sorting the keys.

Supported value types: string, number, bigint, boolean, null, undefined, and arrays of these types. Other types like Symbol, functions, or objects (except arrays) will throw an error.

options

Type: object

strict

Type: boolean
Default: true

Strictly encode URI components. It uses encodeURIComponent if set to false. You probably don't care about this option.

encode

Type: boolean
Default: true

URL encode the keys and values.

arrayFormat

Type: string
Default: 'none'

  • 'bracket': Serialize arrays using bracket representation:
import queryString from 'query-string';

queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'bracket'});
//=> 'foo[]=1&foo[]=2&foo[]=3'
  • 'index': Serialize arrays using index representation:
import queryString from 'query-string';

queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'index'});
//=> 'foo[0]=1&foo[1]=2&foo[2]=3'
  • 'comma': Serialize arrays by separating elements with comma:
import queryString from 'query-string';

queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'comma'});
//=> 'foo=1,2,3'

queryString.stringify({foo: [1, null, '']}, {arrayFormat: 'comma'});
//=> 'foo=1,,'
// Note that typing information for null values is lost
// and `.parse('foo=1,,')` would return `{foo: [1, '', '']}`.
  • 'separator': Serialize arrays by separating elements with a custom character:
import queryString from 'query-string';

queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'separator', arrayFormatSeparator: '|'});
//=> 'foo=1|2|3'
  • 'bracket-separator': Serialize arrays by explicitly post-fixing array names with brackets and separating elements with a custom character:
import queryString from 'query-string';

queryString.stringify({foo: []}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> 'foo[]'

queryString.stringify({foo: ['']}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> 'foo[]='

queryString.stringify({foo: [1]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> 'foo[]=1'

queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> 'foo[]=1|2|3'

queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> 'foo[]=1||3|||6'

queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|', skipNull: true});
//=> 'foo[]=1||3|6'

queryString.stringify({foo: [1, 2, 3], bar: 'fluffy', baz: [4]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
//=> 'foo[]=1|2|3&bar=fluffy&baz[]=4'
  • 'colon-list-separator': Serialize arrays with parameter names that are explicitly marked with :list:
import queryString from 'query-string';

queryString.stringify({foo: ['one', 'two']}, {arrayFormat: 'colon-list-separator'});
//=> 'foo:list=one&foo:list=two'
  • 'none': Serialize arrays by using duplicate keys:
import queryString from 'query-string';

queryString.stringify({foo: [1, 2, 3]});
//=> 'foo=1&foo=2&foo=3'
arrayFormatSeparator

Type: string
Default: ','

The character used to separate array elements when using {arrayFormat: 'separator'}.

sort

Type: Function | boolean

Supports both Function as a custom sorting function or false to disable sorting.

import queryString from 'query-string';

const order = ['c', 'a', 'b'];

queryString.stringify({a: 1, b: 2, c: 3}, {
	sort: (a, b) => order.indexOf(a) - order.indexOf(b)
});
//=> 'c=3&a=1&b=2'
import queryString from 'query-string';

queryString.stringify({b: 1, c: 2, a: 3}, {sort: false});
//=> 'b=1&c=2&a=3'

If omitted, keys are sorted using Array#sort(), which means, converting them to strings and comparing strings in Unicode code point order.

skipNull

Skip keys with null as the value.

Note that keys with undefined as the value are always skipped.

Type: boolean
Default: false

import queryString from 'query-string';

queryString.stringify({a: 1, b: undefined, c: null, d: 4}, {
	skipNull: true
});
//=> 'a=1&d=4'
import queryString from 'query-string';

queryString.stringify({a: undefined, b: null}, {
	skipNull: true
});
//=> ''
skipEmptyString

Skip keys with an empty string as the value.

Type: boolean
Default: false

import queryString from 'query-string';

queryString.stringify({a: 1, b: '', c: '', d: 4}, {
	skipEmptyString: true
});
//=> 'a=1&d=4'
import queryString from 'query-string';

queryString.stringify({a: '', b: ''}, {
	skipEmptyString: true
});
//=> ''
replacer

A function that transforms key-value pairs before stringification.

Type: function
Default: undefined

Similar to the replacer parameter of JSON.stringify(), this function is called for each key-value pair and can be used to transform values before they are stringified. The function receives the key and value, and should return the transformed value. Returning undefined will omit the key-value pair from the resulting query string.

This is useful for custom serialization of non-primitive types like Date:

import queryString from 'query-string';

queryString.stringify({
	date: new Date('2024-01-15T10:30:00Z'),
	name: 'John'
}, {
	replacer: (key, value) => {
		if (value instanceof Date) {
			return value.toISOString();
		}

		return value;
	}
});
//=> 'date=2024-01-15T10%3A30%3A00.000Z&name=John'

You can also use it to filter out keys:

import queryString from 'query-string';

queryString.stringify({
	a: 1,
	b: null,
	c: 3
}, {
	replacer: (key, value) => value === null ? undefined : value
});
//=> 'a=1&c=3'

.extract(string)

Extract a query string from a URL that can be passed into .parse().

queryString.extract('https://foo.bar?foo=bar');
//=> 'foo=bar'

.parseUrl(string, options?)

Extract the URL and the query string as an object.

Returns an object with a url and query property.

If the parseFragmentIdentifier option is true, the object will also contain a fragmentIdentifier property.

import queryString from 'query-string';

queryString.parseUrl('https://foo.bar?foo=bar');
//=> {url: 'https://foo.bar', query: {foo: 'bar'}}

queryString.parseUrl('https://foo.bar?foo=bar#xyz', {parseFragmentIdentifier: true});
//=> {url: 'https://foo.bar', query: {foo: 'bar'}, fragmentIdentifier: 'xyz'}

options

Type: object

The options are the same as for .parse().

Extra options are as below.

parseFragmentIdentifier

Parse the fragment identifier from the URL.

Type: boolean
Default: false

import queryString from 'query-string';

queryString.parseUrl('https://foo.bar?foo=bar#xyz', {parseFragmentIdentifier: true});
//=> {url: 'https://foo.bar', query: {foo: 'bar'}, fragmentIdentifier: 'xyz'}

.stringifyUrl(object, options?)

Stringify an object into a URL with a query string and sorting the keys. The inverse of .parseUrl()

The options are the same as for .stringify().

Returns a string with the URL and a query string.

Query items in the query property overrides queries in the url property.

The fragmentIdentifier property overrides the fragment identifier in the url property.

queryString.stringifyUrl({url: 'https://foo.bar', query: {foo: 'bar'}});
//=> 'https://foo.bar?foo=bar'

queryString.stringifyUrl({url: 'https://foo.bar?foo=baz', query: {foo: 'bar'}});
//=> 'https://foo.bar?foo=bar'

queryString.stringifyUrl({
	url: 'https://foo.bar',
	query: {
		top: 'foo'
	},
	fragmentIdentifier: 'bar'
});
//=> 'https://foo.bar?top=foo#bar'

object

Type: object

url

Type: string

The URL to stringify.

query

Type: object

Query items to add to the URL.

.pick(url, keys, options?)

.pick(url, filter, options?)

Pick query parameters from a URL.

Returns a string with the new URL.

import queryString from 'query-string';

queryString.pick('https://foo.bar?foo=1&bar=2#hello', ['foo']);
//=> 'https://foo.bar?foo=1#hello'

queryString.pick('https://foo.bar?foo=1&bar=2#hello', (name, value) => value === 2, {parseNumbers: true});
//=> 'https://foo.bar?bar=2#hello'

.exclude(url, keys, options?)

.exclude(url, filter, options?)

Exclude query parameters from a URL.

Returns a string with the new URL.

import queryString from 'query-string';

queryString.exclude('https://foo.bar?foo=1&bar=2#hello', ['foo']);
//=> 'https://foo.bar?bar=2#hello'

queryString.exclude('https://foo.bar?foo=1&bar=2#hello', (name, value) => value === 2, {parseNumbers: true});
//=> 'https://foo.bar?foo=1#hello'

url

Type: string

The URL containing the query parameters to filter.

keys

Type: string[]

The names of the query parameters to filter based on the function used.

filter

Type: (key, value) => boolean

A filter predicate that will be provided the name of each query parameter and its value. The parseNumbers and parseBooleans options also affect value.

options

Type: object

Parse options and stringify options.

Nesting

This module intentionally doesn't support nesting as it's not spec'd and varies between implementations, which causes a lot of edge cases.

You're much better off just converting the object to a JSON string:

import queryString from 'query-string';

queryString.stringify({
	foo: 'bar',
	nested: JSON.stringify({
		unicorn: 'cake'
	})
});
//=> 'foo=bar&nested=%7B%22unicorn%22%3A%22cake%22%7D'

However, there is support for multiple instances of the same key:

import queryString from 'query-string';

queryString.parse('likes=cake&name=bob&likes=icecream');
//=> {likes: ['cake', 'icecream'], name: 'bob'}

queryString.stringify({color: ['taupe', 'chartreuse'], id: '515'});
//=> 'color=taupe&color=chartreuse&id=515'

Falsy values

Sometimes you want to unset a key, or maybe just make it present without assigning a value to it. Here is how falsy values are stringified:

import queryString from 'query-string';

queryString.stringify({foo: false});
//=> 'foo=false'

queryString.stringify({foo: null});
//=> 'foo'

queryString.stringify({foo: undefined});
//=> ''

FAQ

Why is it parsing + as a space?

See this answer.