mrkeyoor.com_
Sun 20 Sept 11:42 UTC
npmWeb Frontendupdated 20 Sept 2026

query-string review

query-string 9.5.0 parses flat URL query text into a null-prototype object and serializes supported primitives back to encoded text. Its reason to exist beyond URLSearchParams is policy: repeated, bracketed, indexed, comma, and separator arrays; per-key types; optional number and boolean conversion; sorted output; fragments; and URL pick or exclude helpers. Nested objects remain unsupported. Version 9.5.0 only refreshes dependencies, while 9.4.1 fixed relative URLs containing fragments. Our complete browser import was 8.3 KB minified and 2.9 KB gzipped.

Verdict

query-string 9.5.0 installed in 0.6 seconds as 4 packages and bundled to 2.9 KB gzipped in our sandbox, with 0 audit findings. Install it for typed fields, defined array syntax, or deterministic URL editing; use URLSearchParams for ordinary flat queries and qs for nested contracts.

We installed it

Lab card: what happened when we installed query-stringScreenshot of query-string documentation
Install✓ · 0.6s4 packages on disk · 1 MB
ImportESM import works · require() works · ESM package with exports map
Browser2.9 KBgzipped (8.3 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does query-string install cleanly?

Yes. In a fresh container with an empty cache, npm install query-string finished in 0.6s, leaving 4 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does query-string add to a browser bundle?

2.9 KB gzipped (8.3 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does query-string work with both ESM and CommonJS?

Yes. Both import 'query-string' and require('query-string') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does query-string include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

query-string or qs: which should you use?

qs: Choose it when a server depends on nested bracket objects and depth controls. query-string 9.5.0 installed in 0.6 seconds as 4 packages and bundled to 2.9 KB gzipped in our sandbox, with 0 audit findings.

When should you not use query-string?

The application handles a few flat keys. URLSearchParams is native in current browsers and Node and needs no package.

API stability4/5Version 9.5.0 preserves parse, stringify, parseUrl, stringifyUrl, pick, and exclude, along with the 9.x array, sorting, type, and null-handling options. Its release only updates dependencies, and 9.4.1 repaired relative fragment handling without replacing the API. Major releases have changed runtime floors and module packaging, so teams should still exercise build and interop paths when crossing a major.
Docs5/5The 9.5.0 README provides examples for every array format, per-key types, number and boolean parsing, sorting, encoding, nulls, replacers, fragments, whole-URL operations, filters, plus signs, and the explicit lack of nested objects. It also directs simple cases to URLSearchParams. The page is long, but each option is searchable and its examples expose round-trip differences that short API summaries usually miss.
Maintenance4/5query-string 9.5.0 was released on August 6, 2026, and the unarchived repository was pushed that day. GitHub reported only 2 open issues and pull requests. The release updates dependencies, while 9.4.1 fixed relative URLs with fragments in June. This looks like a mature, deliberately flat utility receiving upkeep, though requests for nested-object semantics are outside its stated direction rather than pending features.
Ecosystem5/5npm counted 24,993,263 downloads from August 19 through 25, 2026, and GitHub showed 6,903 stars. The current package includes declarations, supports the module paths measured in our sandbox, and adds only 2.9 KB gzipped under a full browser import. Native URLSearchParams covers the common baseline, while typed conversion and multiple array dialects preserve a substantial role in SDKs and filtering interfaces.

Use it if

  • A server contract requires bracket, indexed, repeated-key, comma, or custom-separator array parameters.
  • Selected fields should parse as numbers, booleans, strings, or typed arrays while identifiers retain leading zeroes.
  • Canonical URLs or cache keys depend on stable parameter sorting.
  • Code must merge, filter, or replace URL parameters while preserving the path and optional fragment.
Skip it if

Setup reality

We installed query-string 9.5.0 in a fresh Node 22 Bookworm sandbox. npm took 0.6 seconds and left 4 packages using 1 MB. The package was 80 KB unpacked with 3 direct dependencies and no peers. npm audit found 0 known vulnerabilities. It requires Node 18+, ships as ESM behind an exports map, bundles TypeScript declarations, and both require() and ESM import worked in our check.

No credentials or config files are involved. parse() removes a leading ? or # and returns Object.create(null), so parsed.hasOwnProperty is unavailable; use Object.hasOwn(). Values remain strings unless global coercion or the types map changes them. Per-key types override global parseNumbers and parseBooleans, which is the safe place to keep phone numbers, ZIP codes, and opaque IDs as strings.

Array encoding is part of the API contract. Use the same arrayFormat and separator on both sides. Repeated keys, brackets, indices, commas, and bracket separators differ around null and empty values. The package does not encode nested objects. If an endpoint explicitly accepts JSON inside one parameter, serialize that field yourself; otherwise use qs or the server's own convention.

stringify sorts keys by default and always omits undefined. Null and empty strings remain unless skipNull or skipEmptyString is set. parseUrl returns a fragment only with parseFragmentIdentifier, while stringifyUrl can set one. A raw + decodes as a space, so a literal plus must arrive as %2B. Our browser bundle was 8.3 KB minified and 2.9 KB gzipped. Version 9.5.0 has no new API behavior beyond dependency updates.

Patterns

Read flat parameters parse-flat-query

import queryString from 'query-string';

const params = queryString.parse('?q=paper&page=2');
console.log(params.q, params.page);

The result has a null prototype. Use Object.hasOwn(params, key), not params.hasOwnProperty(key).

Write sorted parameters serialize-stable-query

queryString.stringify({ q: 'paper', page: 2 });
queryString.stringify({ b: 1, a: 2 }, { sort: false });

Keys sort by default. sort: false retains insertion order for callers that require it.

Type specific query values parse-typed-fields

const params = queryString.parse('?age=20&id=0012&active=true', {
  parseNumbers: true,
  parseBooleans: true,
  types: { id: 'string' },
});

Per-key types outrank global coercion, preserving the leading zero in id.

Match bracket array syntax encode-bracket-array

const options = { arrayFormat: 'bracket' };
const text = queryString.stringify({ ids: [1, 2] }, options);
const back = queryString.parse(text, options);

Use one arrayFormat for writing and reading. A different format can change key names or array shape.

Write a comma-separated array encode-comma-array

const text = queryString.stringify(
  { tags: ['paper', 'ink'] },
  { arrayFormat: 'comma' },
);

Comma format is ambiguous when values themselves contain separators unless both sides apply matching encoding rules.

Parse a full URL split-url-and-query

const result = queryString.parseUrl(
  'https://example.com/search?q=paper#results',
  { parseFragmentIdentifier: true },
);

The fragmentIdentifier property appears only when parseFragmentIdentifier is enabled.

Replace parameters in a URL merge-url-query

const url = queryString.stringifyUrl({
  url: 'https://example.com/search?q=old&keep=yes',
  query: { q: 'new', page: 2 },
});

New values replace matching keys. Default sorting can reorder existing parameters.

Exclude matching parameters remove-tracking-keys

const clean = queryString.exclude(
  'https://example.com?id=7&utm_source=x&utm_medium=y',
  key => key.startsWith('utm_'),
);

exclude accepts a predicate or key list and preserves any URL fragment.

Skip null and blank filters omit-empty-filters

const text = queryString.stringify(
  { q: 'paper', brand: '', minPrice: null, page: 1 },
  { skipNull: true, skipEmptyString: true },
);

undefined is always omitted; null and empty strings require their separate skip options.

Convert unsupported values serialize-date-value

const text = queryString.stringify(
  { since: new Date('2026-01-15T10:30:00Z') },
  { replacer: (_key, value) => value instanceof Date ? value.toISOString() : value },
);

Date and plain object values are unsupported directly. A replacer must return a supported primitive or undefined.

Encode one explicit JSON field carry-json-parameter

const text = queryString.stringify({
  view: 'grid',
  filters: JSON.stringify({ brand: 'canon', inStock: true }),
});
const filters = JSON.parse(queryString.parse(text).filters);

This package has no nested query syntax. Use this only when the endpoint explicitly defines a JSON-valued parameter.

Encode a literal plus sign preserve-plus-character

const text = queryString.stringify({ phone: '+15551234567' });
const params = queryString.parse(text);

An unescaped + decodes as a space. stringify emits %2B so the round trip preserves the plus.

Alternatives

PackageRegistryPick it when
qsnpmChoose it when a server depends on nested bracket objects and depth controls.
querystringifynpmChoose it for a smaller flat parser with fewer array and type policies.
ufonpmChoose it when path joining, URL normalization, and queries belong in one utility.

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.