query-string vs uri-js vs url-join vs url-parse vs url-template
URL Manipulation and Parsing Strategies in JavaScript
query-stringuri-jsurl-joinurl-parseurl-templateSimilar Packages:

URL Manipulation and Parsing Strategies in JavaScript

These five libraries address different aspects of URL handling in JavaScript applications. query-string focuses specifically on parsing and building query parameters. uri-js provides strict RFC 3986 compliance for full URI resolution and normalization. url-join is a lightweight utility for concatenating path segments safely. url-parse offers a robust parser for full URLs with support for relative paths and custom protocols. url-template implements RFC 6570 for expanding URI templates with variables. Together, they cover the spectrum from simple query handling to complex URI routing logic.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
query-string06,90859.1 kB2a month agoMIT
uri-js0317-306 years agoBSD-2-Clause
url-join03664.74 kB6-MIT
url-parse01,03463 kB16-MIT
url-template01957.99 kB33 years agoBSD-3-Clause

URL Manipulation and Parsing Strategies in JavaScript

When working with URLs in JavaScript, developers often face a fragmented ecosystem. Some tools handle query parameters, others focus on path joining, and some enforce strict RFC standards. The packages query-string, uri-js, url-join, url-parse, and url-template each solve specific parts of this puzzle. Let's compare how they tackle common engineering tasks.

🔍 Parsing URLs: Query Params vs Full URIs

Parsing is the first step in understanding a URL. Different libraries offer different levels of depth.

query-string focuses exclusively on the search parameters.

  • It extracts the query part and returns an object.
  • It ignores the protocol, host, and path.
// query-string: Parse query params only
import queryString from 'query-string';

const parsed = queryString.parse('?search=js&limit=10');
// { search: 'js', limit: '10' }

uri-js parses the entire URI structure strictly.

  • It breaks down scheme, user info, host, port, path, query, and fragment.
  • Ideal for validation and normalization.
// uri-js: Parse full URI
import { parse } from 'uri-js';

const parsed = parse('https://example.com:8080/path?q=1');
// { scheme: 'https', host: 'example.com', port: 8080, path: '/path', query: 'q=1' }

url-join does not parse URLs.

  • It is a builder only.
  • Attempting to parse with it will fail as there is no parse method.
// url-join: No parsing capability
import urlJoin from 'url-join';

// urlJoin.parse is undefined
// Use only for constructing strings from parts

url-parse parses full URLs with flexibility.

  • It supports relative URLs and custom protocols.
  • Returns an object with properties like protocol, hostname, query.
// url-parse: Parse full URL
import UrlParse from 'url-parse';

const parsed = new UrlParse('https://example.com/path?q=1');
// parsed.protocol => 'https:', parsed.query => '?q=1'

url-template does not parse standard URLs.

  • It parses template strings with expressions like {id}.
  • Used for defining patterns rather than reading existing URLs.
// url-template: Parse template pattern
import { parse } from 'url-template';

const template = parse('/users/{id}');
// Returns a template object for expansion, not URL data

🛠️ Building and Joining URL Segments

Constructing URLs safely without double slashes or missing separators is a common pain point.

query-string builds query strings from objects.

  • It handles encoding and array formatting.
  • You must combine it with a path tool for full URLs.
// query-string: Stringify params
import queryString from 'query-string';

const search = queryString.stringify({ q: 'js', limit: 10 });
// 'q=js&limit=10'

uri-js serializes URI components back into a string.

  • It ensures the output is RFC compliant.
  • Useful after modifying parts of a parsed URI.
// uri-js: Serialize URI
import { serialize } from 'uri-js';

const uri = serialize({ scheme: 'https', host: 'example.com', path: '/api' });
// 'https://example.com/api'

url-join joins path segments cleanly.

  • It removes duplicate slashes automatically.
  • Best for appending paths to a base URL.
// url-join: Join path segments
import urlJoin from 'url-join';

const url = urlJoin('https://example.com', '/api/', '/users');
// 'https://example.com/api/users'

url-parse allows modifying parts and rebuilding.

  • You can set properties like query or pathname and call toString().
  • Good for mutating existing URLs.
// url-parse: Modify and rebuild
import UrlParse from 'url-parse';

const url = new UrlParse('https://example.com');
url.set('pathname', '/api/users');
// url.toString() => 'https://example.com/api/users'

url-template expands templates with data.

  • It fills in variables defined in the template string.
  • Perfect for RESTful API resource paths.
// url-template: Expand template
import { parse } from 'url-template';

const template = parse('/users/{id}');
const url = template.expand({ id: 123 });
// '/users/123'

📜 Standards Compliance: RFC 3986 and 6570

For tools that interact with multiple systems, following standards prevents bugs.

query-string follows common web practices.

  • It handles encoding but is not strictly RFC 3986 focused.
  • Great for browser-based query manipulation.
// query-string: Encoding handling
import queryString from 'query-string';

// Handles spaces as '+' or '%20' based on options
queryString.stringify({ q: 'hello world' }, { encode: true });

uri-js is strictly RFC 3986 compliant.

  • It handles edge cases like IP literals, IPv6, and normalization.
  • Use this when interoperability is critical.
// uri-js: Normalization
import { normalize } from 'uri-js';

// Normalizes case and encoding
normalize('HTTP://EXAMPLE.com:80/'); 
// 'http://example.com/'

url-join focuses on path syntax.

  • It does not validate RFC compliance.
  • It assumes inputs are valid path segments.
// url-join: No validation
import urlJoin from 'url-join';

// Joins regardless of content validity
urlJoin('http://test', 'path');

url-parse supports custom protocols.

  • It is flexible but less strict than uri-js.
  • Allows non-standard schemes which can be useful or risky.
// url-parse: Custom protocols
import UrlParse from 'url-parse';

const parsed = new UrlParse('custom://resource');
// parsed.protocol => 'custom:'

url-template implements RFC 6570.

  • It supports levels 1 through 4 of the template specification.
  • Essential for Hypermedia APIs (HATEOAS).
// url-template: RFC 6570 operators
import { parse } from 'url-template';

// Uses template operators like {?q}
const template = parse('/search{?q}');
template.expand({ q: 'js' }); // '/search?q=js'

🌐 Real-World Scenarios

Scenario 1: Building Filtered List URLs

You need to create a URL with dynamic query parameters for a data grid.

  • Best choice: query-string
  • Why? It handles arrays and encoding cleanly without extra setup.
// query-string: Filter URL
import queryString from 'query-string';

const filters = { status: 'active', tags: ['a', 'b'] };
const url = `/dashboard?${queryString.stringify(filters)}`;

Scenario 2: Resolving Relative Links

You are building a crawler or proxy that must resolve relative links against a base.

  • Best choice: uri-js
  • Why? It implements the RFC 3986 resolution algorithm correctly.
// uri-js: Resolve relative
import { resolve } from 'uri-js';

const base = 'https://example.com/a/b/';
const relative = '../c';
const absolute = resolve(base, relative);
// 'https://example.com/a/c'

Scenario 3: Constructing API Endpoints

You have a base API URL and need to append dynamic resource paths.

  • Best choice: url-join
  • Why? It prevents double slashes when concatenating variables.
// url-join: API Endpoint
import urlJoin from 'url-join';

const base = process.env.API_URL; // 'https://api.test.com/'
const endpoint = urlJoin(base, '/v1', '/users', userId);

Scenario 4: Parsing Legacy URLs

You need to parse URLs in an environment without the native URL API (e.g., old Node or IE).

  • Best choice: url-parse
  • Why? It works everywhere and supports relative URLs natively.
// url-parse: Legacy Support
import UrlParse from 'url-parse';

const url = new UrlParse('/path/to/page', 'https://base.com');
// Correctly resolves against base

Scenario 5: Hypermedia API Clients

Your API returns templates like /orders/{orderId}/items instead of fixed paths.

  • Best choice: url-template
  • Why? It is the only library here designed for RFC 6570 expansion.
// url-template: Hypermedia
import { parse } from 'url-template';

const link = parse('/orders/{id}/items');
const url = link.expand({ id: 55 });

📊 Summary Table

PackagePrimary FocusRFC ComplianceParses Full URLBuilds URLTemplate Support
query-stringQuery ParamsLow❌ (Query only)✅ (Query only)
uri-jsFull URI LogicHigh (3986)
url-joinPath ConcatenationLow✅ (Paths)
url-parseURL ParsingMedium
url-templateURI TemplatesHigh (6570)❌ (Templates)✅ (Expansion)

💡 The Big Picture

query-string is the daily driver for frontend developers working with search params. It is simple and effective for browser-based tasks.

uri-js is the heavy-duty tool for backend or infrastructure code where standards matter. Use it for validation and resolution logic.

url-join is the utility player for string construction. Keep it in your toolkit for cleaning up path concatenation.

url-parse is the reliable parser for environments where the native URL class is not an option. It balances features and compatibility.

url-template is the specialist for Hypermedia APIs. If your backend sends templates, this is the only choice.

Final Thought: Modern browsers have a native URL class that covers many of these cases. However, for query manipulation, template expansion, or strict RFC compliance in Node.js, these libraries remain essential. Choose the tool that matches your specific URL problem — don't import a heavy URI resolver if you just need to join two paths.

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

  • query-string:

    Choose query-string when your primary need is handling query parameters in the browser or Node.js. It is ideal for reading search params from window.location or building filtered list URLs. It does not handle full URL path manipulation, so pair it with other tools if you need to modify the pathname.

  • uri-js:

    Choose uri-js when you need strict RFC 3986 compliance, such as validating URIs, resolving relative references, or normalizing URLs for comparison. It is heavier than other options but essential for servers, proxies, or tools where standard compliance matters more than bundle size.

  • url-join:

    Choose url-join when you simply need to concatenate URL path segments without worrying about double slashes or missing separators. It is perfect for constructing API endpoints from base URLs and paths. It does not parse URLs, so use it only for building strings.

  • url-parse:

    Choose url-parse when you need to parse full URLs including protocol, host, and port, especially in environments where the native URL API is unavailable or insufficient. It supports relative URLs and custom protocols, making it suitable for older browsers or Node.js tools.

  • url-template:

    Choose url-template when your API or routing system uses RFC 6570 URI templates (e.g., /users/{id}). It is specialized for expanding templates with variables rather than parsing existing URLs. Use it for hypermedia APIs or dynamic route generation.

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.

[!TIP] Consider using URLSearchParams for simple use cases. It's a native browser API that handles basic query string operations.

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.