urlSearchParams.toString()

Serializes the parameters to a percent-encoded query string, with spaces written as plus signs.

Signature
urlSearchParams.toString()
  • Added in Node.js v7.5.0, v6.13.0

Return value

stringThe search parameters serialized as a string, with characters percent-encoded where necessary. No leading '?' is included.

toString() renders the whole collection using application/x-www-form-urlencoded serialization: pairs joined by &, name and value joined by =, and every character that would be ambiguous escaped. Insertion order is preserved.

When to reach for it

Reach for it whenever you need the query as text — assigning to url.search, composing a request line, or logging. You rarely need to call it explicitly: string concatenation, template literals and String() all invoke it, and passing a URLSearchParams as a fetch body serializes it the same way while setting the form-urlencoded content type.

What trips people up

Spaces become +, not %20. That is correct form-urlencoding and every conforming parser decodes it back to a space, but it differs from encodeURIComponent('node js'), which yields node%20js. Services that decode the query with their own regex sometimes leave the + in place — if you hit one, build that value with encodeURIComponent yourself.

There is no leading ?. Writing url.href + params.toString() produces a malformed URL; assign to url.search (which adds the ?) or prefix it yourself. Note also that url.search does include the ?, so the two are not interchangeable.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Attach a built parameter set to a URL by assigning to url.search
  • Produce a form-urlencoded POST body for an OAuth token request
  • Generate a stable cache key from sorted request parameters
  • Log the exact query string a request will send

Frequently asked questions

Why does URLSearchParams encode spaces as + instead of %20?

Because it follows the application/x-www-form-urlencoded serializer, where a space is +. Standards-compliant parsers decode it back to a space; if a specific service does not, encode that value with encodeURIComponent and build the string manually.

Does toString() include the leading question mark?

No — it returns only the pairs, so 'a=1&b=2'. Assign it to url.search, which adds the ?, or prefix it yourself, and remember url.search does include the ? when reading.

How do I convert an object to a query string in Node?

new URLSearchParams(obj).toString() does it in one step, coercing values to strings and escaping them. Remove null and undefined fields first, since they serialize as the text 'null' and 'undefined'.

More examples

Attaching parameters to a URL correctly

Assigning to url.search inserts the ? for you. The final line shows the failure mode: without a separator the query is glued onto the path, producing /searchpage=2&q=red+shoes.

Example · javascript
const params = new URLSearchParams({ page: 2, q: 'red shoes' });
const url = new URL('https://shop.example.com/search');

url.search = params.toString();
console.log(url.href);

console.log('search includes ?:', JSON.stringify(url.search));
console.log('toString does not:', JSON.stringify(params.toString()));
console.log('naive concat:', 'https://shop.example.com/search' + params.toString());

A stable cache key from sorted parameters

sort() puts pairs into a canonical order so two logically identical URLs hash to the same key. The template literal coerces searchParams via toString(), which is why no explicit call appears.

Example · javascript
function cacheKey(href) {
  const u = new URL(href);
  u.searchParams.sort();
  return `${u.origin}${u.pathname}?${u.searchParams}`;
}

console.log(cacheKey('https://api.example.com/items?b=2&a=1'));
console.log(cacheKey('https://api.example.com/items?a=1&b=2'));
console.log(cacheKey('https://api.example.com/items?b=2&a=1') === cacheKey('https://api.example.com/items?a=1&b=2'));

Empty and single-value edge cases

An empty collection serializes to '', so guard before adding a '?'. A bare flag gains an '=' on the way out, and null/undefined are stringified literally rather than dropped — filter those out before constructing.

Example · javascript
console.log(JSON.stringify(new URLSearchParams().toString()));
console.log(JSON.stringify(new URLSearchParams('flag').toString()));
console.log(JSON.stringify(new URLSearchParams({ a: '' }).toString()));
console.log(JSON.stringify(new URLSearchParams({ a: null, b: undefined }).toString()));

Discussion

  • Be the first to comment on this lesson.