NodeJSThe querystring Module

The querystring Module

node:querystring parses and serializes the key=value&key2=value2 strings that live after the ? in a URL or inside a form-encoded request body. It predates the web-standard URLSearchParams — and understanding when to use which is the real lesson of this page.

The two core functions

Function

Direction

Example

querystring.parse(str)

string → object

'a=1&b=2'{ a: '1', b: '2' }

querystring.stringify(obj)

object → string

{ a: 1, b: 2 }'a=1&b=2'

querystring.escape(str)

Percent-encode one component

%20

querystring.unescape(str)

Percent-decode one component

%20

JS
import querystring from 'node:querystring'

const parsed = querystring.parse('name=Ada&lang=js&lang=ts')
// → { name: 'Ada', lang: ['js', 'ts'] }   repeated key → array

const str = querystring.stringify({ name: 'Ada Lovelace', page: 2 })
// → 'name=Ada%20Lovelace&page=2'
Repeated keys become arrays
When a key appears more than once, `parse` collects the values into an array (`lang=js&lang=ts` → `['js', 'ts']`). `stringify` does the reverse: an array value expands into repeated keys. This mirrors how HTML forms send multi-select fields.
Custom separators

Unlike URLSearchParams, querystring lets you change the separator and assignment characters — useful for parsing cookie-like or semicolon-delimited strings:

JS
querystring.parse('a:1;b:2', ';', ':')
// → { a: '1', b: '2' }   sep=';'  eq=':'

querystring.stringify({ a: 1, b: 2 }, ';', ':')
// → 'a:1;b:2'
querystring vs URLSearchParams

This is the decision that matters. The web-standard URLSearchParams (from the url module) is the modern default; querystring survives for legacy code and its custom-separator flexibility:

querystring

URLSearchParams

Standard

Node-specific (legacy)

WHATWG — works in browsers too

Returns

A plain object

An iterable object with methods

Custom separators

Yes (;, :, …)

No — always & and =

Space encoding

%20

+ (form style)

Recommended for new code

No

Yes

The same task, the modern way

JS
const params = new URLSearchParams('name=Ada&lang=js&lang=ts')
params.get('name')       // 'Ada'
params.getAll('lang')    // ['js', 'ts']
params.toString()        // 'name=Ada&lang=js&lang=ts'
They encode spaces differently — don't mix them
`querystring.escape` encodes a space as `%20`; `URLSearchParams` encodes it as `+` (the HTML-form convention). If you serialize with one and parse with the other, spaces can come back wrong. Pick one tool per code path. For anything URL-related, prefer `URLSearchParams`.
A real use: parsing a POST body

Form submissions with Content-Type: application/x-www-form-urlencoded arrive as a query-string body. Here is the bare-Node way to read one (frameworks like Express do this for you):

JS
import { createServer } from 'node:http'

createServer((req, res) => {
  let body = ''
  req.on('data', (chunk) => { body += chunk })
  req.on('end', () => {
    const form = new URLSearchParams(body)
    res.end(`Hello, ${form.get('name')}`)
  })
}).listen(3000)
When to use each — the short rule
  • New code, web URLs, isomorphic (Node + browser) → URLSearchParams.

  • Need a non-&/= separator (cookies, custom formats) → querystring.

  • Maintaining old Node code already using it → leave querystring in place.

Next
Hashing, encryption, random tokens, and UUIDs — the security toolkit: [The crypto Module](/nodejs/crypto-module).