query-string vs uri-js vs uri-template vs url-parse vs whatwg-url
前端 URL 与查询字符串处理库选型指南
query-stringuri-jsuri-templateurl-parsewhatwg-url类似的npm包:

前端 URL 与查询字符串处理库选型指南

query-stringuri-jsuri-templateurl-parsewhatwg-url 都是用于处理 URL 和 URI 相关操作的 JavaScript 库,但各自侧重点不同。query-string 专注于查询字符串的解析与序列化,支持嵌套对象和数组;uri-js 提供符合 RFC 3986 标准的完整 URI 解析与构造,并支持国际化资源标识符(IRI);uri-template 专门用于处理 RFC 6570 定义的 URI 模板,适用于动态生成 API 路径;url-parse 是一个轻量级 URL 解析器,支持相对 URL 解析和自定义协议;whatwg-url 则严格遵循 WHATWG URL 标准,行为与浏览器原生 URL 对象一致,适合需要前后端一致性的场景。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
query-string06,90657.7 kB26 个月前MIT
uri-js0317-305 年前BSD-2-Clause
uri-template044-14 年前MIT
url-parse01,03963 kB14-MIT
whatwg-url0411101 kB716 天前MIT

URL 与查询字符串处理库深度对比:query-string、uri-js、uri-template、url-parse、whatwg-url

在现代前端开发中,解析、构建和操作 URL 是常见但容易出错的任务。从简单的查询参数读取到复杂的 URI 模板展开,不同场景对工具的要求差异很大。本文将深入对比五个主流 npm 包 —— query-stringuri-jsuri-templateurl-parsewhatwg-url —— 帮助你在架构决策中做出精准选择。

🔍 核心功能定位

首先明确每个库的设计目标,这是选型的第一步。

  • query-string:专注于查询字符串(query string)的序列化与反序列化,支持嵌套对象、数组等复杂结构。
  • uri-js:提供完整的 RFC 3986 兼容 URI 解析与构造,并支持 IRIs(国际化资源标识符)。
  • uri-template:专门用于URI 模板(RFC 6570)的解析与展开,适用于 API 路径动态生成。
  • url-parse:轻量级 URL 解析器,支持自定义协议、相对 URL 处理和宽松模式
  • whatwg-url:严格遵循 WHATWG URL Standard 的实现,行为与浏览器原生 URL 对象一致。

⚠️ 注意:截至 2024 年,所有五个包均未被官方标记为废弃(deprecated),可安全用于新项目。

🧪 查询字符串处理能力对比

场景:解析 ?foo=bar&baz[qux]=123

query-string 支持深度嵌套语法(类似 PHP 风格):

import queryString from 'query-string';

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

uri-js 不直接处理查询字符串,需配合其 parse 方法后手动解析 query 字段:

import * as URI from 'uri-js';

const parts = URI.parse('https://example.com?foo=bar&baz[qux]=123');
// parts.query === 'foo=bar&baz[qux]=123'
// 需额外逻辑解析 query

uri-template 完全不处理查询字符串,仅关注路径模板。

url-parse 提供基础查询字符串解析,但默认返回原始字符串:

import Url from 'url-parse';

const url = new Url('https://example.com?foo=bar&baz=123');
// url.query === '?foo=bar&baz=123'
// 若启用 parseQueryString 选项:
const url2 = new Url('https://example.com?foo=bar', true);
// url2.query === { foo: 'bar' }

whatwg-url 通过 URLSearchParams 接口提供标准查询参数操作:

import { URL } from 'whatwg-url';

const url = new URL('https://example.com?foo=bar&baz=123');
const params = url.searchParams;
params.get('foo'); // 'bar'
// 不支持嵌套结构,所有值均为字符串

💡 结论:若需处理嵌套或数组形式的查询参数query-string 是唯一开箱即用的选择。

🧱 URL 解析与构造能力

场景:解析 https://user:pass@example.com:8080/path?query#frag

uri-js 返回符合 RFC 的完整结构:

import * as URI from 'uri-js';

const parts = URI.parse('https://user:pass@example.com:8080/path?query#frag');
// {
//   scheme: 'https',
//   userinfo: 'user:pass',
//   host: 'example.com',
//   port: 8080,
//   path: '/path',
//   query: 'query',
//   fragment: 'frag'
// }

url-parse 提供类似结果,但字段命名更贴近 Node.js:

import Url from 'url-parse';

const url = new Url('https://user:pass@example.com:8080/path?query#frag');
// {
//   protocol: 'https:',
//   username: 'user',
//   password: 'pass',
//   hostname: 'example.com',
//   port: '8080',
//   pathname: '/path',
//   query: 'query',
//   hash: '#frag'
// }

whatwg-url 行为与浏览器一致:

import { URL } from 'whatwg-url';

const url = new URL('https://user:pass@example.com:8080/path?query#frag');
// url.protocol === 'https:'
// url.username === 'user'
// url.password === 'pass'
// url.hostname === 'example.com'
// url.port === '8080'
// url.pathname === '/path'
// url.search === '?query'
// url.hash === '#frag'

query-stringuri-template 不提供完整 URL 解析功能。

💡 结论:若需严格遵循浏览器行为(如在 SSR 中模拟客户端 URL 处理),选 whatwg-url;若需RFC 合规性或 IRI 支持,选 uri-js;若需轻量级且支持相对 URL,选 url-parse

🧩 URI 模板支持

只有 uri-template 专精于此:

import { parse } from 'uri-template';

const template = parse('/users{/id}{?active,role}');
const url1 = template.expand({ id: 123 });
// '/users/123'
const url2 = template.expand({ id: 123, active: true, role: 'admin' });
// '/users/123?active=true&role=admin'

其他库均不支持 URI 模板语法(如 {var}{?query} 等)。

💡 结论:若项目涉及 HAL、OpenAPI 或其他使用 URI 模板的 API 规范uri-template 是必选项。

⚙️ 特殊场景处理能力

相对 URL 解析

url-parse 支持基于 base URL 解析相对路径:

import Url from 'url-parse';

const relative = new Url('../other', 'https://example.com/base/path/');
// relative.href === 'https://example.com/base/other'

whatwg-url 也支持(通过第二个参数):

import { URL } from 'whatwg-url';

const url = new URL('../other', 'https://example.com/base/path/');
// url.href === 'https://example.com/base/other'

uri-js 需调用 resolve 方法:

import * as URI from 'uri-js';

const resolved = URI.resolve('https://example.com/base/path/', '../other');
// 'https://example.com/base/other'

国际化域名(IDN)

uri-js 原生支持 IRI(国际化资源标识符),可处理 Unicode 域名:

import * as URI from 'uri-js';

URI.parse('https://例子.测试/'); // 正确解析

whatwg-url 也支持 IDN(通过 punycode 转换),行为与浏览器一致。

url-parse 默认不处理 IDN,需额外配置。

📊 选型决策矩阵

需求场景推荐库
复杂查询参数(嵌套/数组)query-string
严格浏览器兼容 URL 行为whatwg-url
RFC 3986 / IRI 支持uri-js
URI 模板展开uri-template
轻量级解析 + 相对 URLurl-parse
服务端渲染中模拟浏览器 URLwhatwg-url

💡 实战建议

  • 避免混用多个库:除非有明确分层(如用 uri-template 生成路径,再用 query-string 拼接参数),否则会增加 bundle 体积和认知负担。
  • 优先考虑标准:若目标环境是现代浏览器或兼容 WHATWG 的运行时(如 Deno、新版本 Node.js),直接使用原生 URLURLSearchParams 可能无需额外依赖。
  • 注意编码差异:不同库对特殊字符(如 +、空格)的处理可能不同。query-string 默认将 + 视为空格,而 whatwg-url 不会 —— 这可能导致与后端不一致。

🔄 组合使用示例

有时需要组合多个库:

// 使用 uri-template 生成基础路径
import { parse } from 'uri-template';
import queryString from 'query-string';

const template = parse('/api/v1/users{/userId}{/action}');
const basePath = template.expand({ userId: 123, action: 'profile' });
// '/api/v1/users/123/profile'

// 使用 query-string 添加复杂查询参数
const query = queryString.stringify({
  filters: { status: 'active', type: ['premium', 'trial'] },
  page: 1
});
// 'filters[status]=active&filters[type][0]=premium&filters[type][1]=trial&page=1'

const finalUrl = `${basePath}?${query}`;

✅ 总结

没有“最好”的库,只有“最合适”的工具:

  • query-string:查询字符串领域的瑞士军刀,尤其适合表单、过滤器等复杂参数场景。
  • uri-js:RFC 合规性最强,适合需要严格 URI 验证或国际化支持的系统。
  • uri-template:URI 模板的事实标准实现,API 客户端生成器的首选。
  • url-parse:轻量、灵活,适合需要处理相对 URL 或自定义协议的通用解析任务。
  • whatwg-url:浏览器行为的权威实现,确保前后端 URL 处理一致性。

根据你的具体需求 —— 是解析、构造、模板展开,还是查询参数处理 —— 选择最专注的那个工具,往往比追求“全能”更高效、更可靠。

如何选择: query-string vs uri-js vs uri-template vs url-parse vs whatwg-url

  • query-string:

    当你需要处理复杂的查询字符串(如嵌套对象、数组、布尔值自动转换)时,应选择 query-string。它在表单序列化、过滤器参数构建等场景中表现优异,且提供了丰富的解析和字符串化选项。如果你的应用大量依赖查询参数传递结构化数据,它是最佳选择。

  • uri-js:

    当你需要严格遵循 RFC 3986 标准进行 URI 解析、验证或构造,或必须支持国际化域名(IDN/IRI)时,应选择 uri-js。它适合构建需要高合规性的系统(如代理、网关或 URI 工具库),但若只需基础 URL 操作则可能过于重量级。

  • uri-template:

    当你需要根据 RFC 6570 规范展开或解析 URI 模板(例如 /users/{id}{?active})时,必须选择 uri-template。它在构建 API 客户端、HAL 浏览器或任何依赖 URI 模板的超媒体驱动应用中不可或缺,但不适用于普通 URL 解析任务。

  • url-parse:

    当你需要一个轻量级、灵活的 URL 解析器,且要求支持相对 URL 解析、宽松模式或自定义协议时,应选择 url-parse。它在通用 URL 操作(如链接规范化、重定向处理)中非常实用,但不提供查询字符串高级处理或 URI 模板支持。

  • whatwg-url:

    当你需要确保 URL 行为与现代浏览器完全一致(例如在 SSR 中模拟客户端 URL 处理),或项目已基于 WHATWG 标准构建时,应选择 whatwg-url。它适合需要前后端 URL 逻辑统一的场景,但不支持嵌套查询参数或 URI 模板。

query-string的README

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.