Encoding and Decoding Query Strings in Node.js

Node.js gives you two built-in ways to build and parse query strings: URLSearchParams and the older querystring module. Both handle percent-encoding for you automatically — but they behave differently enough with arrays and special characters that picking the wrong one causes bugs. Here's how to use each.

Building a query string with URLSearchParams

URLSearchParams is the modern, web-standard way to build query strings — it works identically in Node.js and browsers. Pass it a plain object or array of pairs, and it handles encoding automatically.

const params = new URLSearchParams({
  q: 'node.js & express',
  page: '2',
  sort: 'desc',
});

console.log(params.toString());
// → 'q=node.js+%26+express&page=2&sort=desc'

const url = `https://api.example.com/search?${params.toString()}`;

Parsing a query string with URLSearchParams

import { URL } from 'url';

const url = new URL('https://api.example.com/search?q=node.js+%26+express&page=2');

url.searchParams.get('q');     // 'node.js & express' — decoded automatically
url.searchParams.get('page');  // '2'
url.searchParams.has('sort');  // false

// Or parse a bare query string directly:
const params = new URLSearchParams('q=hello+world&page=3');
params.get('q'); // 'hello world'

Handling repeated keys (arrays)

A common source of bugs: using a plain object with an array value doesn't produce repeated key=value pairs automatically. Use .append() in a loop instead, and .getAll() to read them back.

const params = new URLSearchParams();
for (const tag of ['nodejs', 'backend', 'api']) {
  params.append('tag', tag);
}

console.log(params.toString());
// → 'tag=nodejs&tag=backend&tag=api'

// Reading them back
const parsed = new URLSearchParams('tag=nodejs&tag=backend&tag=api');
parsed.getAll('tag');
// → ['nodejs', 'backend', 'api']

The querystring module (legacy, still works)

The older querystring module is still built into Node.js. It handles arrays natively (unlike a plain object passed to URLSearchParams), which is occasionally convenient, but Node's own documentation recommends URLSearchParams for new code.

import querystring from 'querystring';

// Build — arrays work directly, unlike URLSearchParams(object)
const qs = querystring.stringify({ tag: ['nodejs', 'backend'], page: 2 });
console.log(qs);
// → 'tag=nodejs&tag=backend&page=2'

// Parse
const parsed = querystring.parse('tag=nodejs&tag=backend&page=2');
console.log(parsed);
// → { tag: ['nodejs', 'backend'], page: '2' }

Using query strings in an Express route

import express from 'express';
const app = express();

// GET /search?q=node.js%20tutorial&page=2
app.get('/search', (req, res) => {
  // Express parses req.query for you using the querystring module internally
  const { q, page = '1' } = req.query;
  res.json({ query: q, page: Number(page) });
});

// Building a link to another endpoint with query params
app.get('/next-page-link', (req, res) => {
  const params = new URLSearchParams({ q: req.query.q, page: '3' });
  res.json({ next: `/search?${params.toString()}` });
});

URLSearchParams vs querystring — quick comparison

  • URLSearchParams — web standard, works in browsers too, recommended by Node.js docs, cleaner iteration API.
  • querystring — Node-only, marked legacy, but handles array values from a plain object without extra loops.
  • Both automatically percent-encode and decode values — you should rarely call encodeURIComponent manually when using either.

Frequently Asked Questions

Should I use URLSearchParams or the querystring module in Node.js?

Prefer URLSearchParams for new code — it is a web standard also available in browsers, has a cleaner API, and is actively maintained. The querystring module still works and is slightly faster for simple cases, but Node.js docs mark it as legacy in favor of URLSearchParams.

How do I build a query string from an object in Node.js?

Pass the object directly to new URLSearchParams(obj) and call .toString(). URLSearchParams automatically percent-encodes keys and values for you, so you never need to call encodeURIComponent manually.

How do I handle repeated query parameters like ?tag=a&tag=b in Node.js?

Use URLSearchParams.append() to add multiple values under the same key, and .getAll(key) to retrieve them all as an array. Using .set() or a plain object will overwrite earlier values instead of preserving duplicates.

Try the Free URL Encoder

Need to quickly encode a query parameter value by hand? Use our free online tool for instant percent-encoding, no Node.js required.

Related articles