The modern answer is URLSearchParams — it decodes values for you, handles repeated keys, and is built into every browser and Node.js. Here’s how to use it, plus the edge cases (arrays, + vs %20, nested objects) that trip people up.
Use the built-in URLSearchParams. It parses a query string into key/value pairs and decodes each value automatically:
const params = new URLSearchParams('?q=hello world&page=2');
params.get('q'); // "hello world" (decoded)
params.get('page'); // "2"
params.has('page'); // true
You can build it from location.search in the browser to read the current page’s query string:
const params = new URLSearchParams(location.search);
const query = params.get('q');
Query strings can repeat a key — ?tag=js&tag=url is two values for tag. get() returns only the first; getAll() returns every value:
const params = new URLSearchParams('tag=js&tag=url&tag=web');
params.get('tag'); // "js" (first only)
params.getAll('tag'); // ["js","url","web"]
for (const [key, value] of params) {
console.log(key, '=', value);
}
Object.fromEntries is the quick way — but note it collapses repeated keys to the last value, so only use it when keys are unique:
const obj = Object.fromEntries(new URLSearchParams('a=1&b=2'));
// { a: "1", b: "2" }
// Repeated keys need manual handling:
const params = new URLSearchParams('tag=js&tag=url');
const grouped = {};
for (const [k, v] of params) {
grouped[k] = grouped[k] ? [...[].concat(grouped[k]), v] : v;
}
// { tag: ["js","url"] }
In a query string, + means a space (a form-encoding convention), and URLSearchParams decodes it as such. In a path, + is a literal plus. So parsing ?q=a+b gives "a b", which is usually what you want — but if your data legitimately contains a plus, it must arrive as %2B.
new URLSearchParams('q=a+b').get('q'); // "a b"
new URLSearchParams('q=a%2Bb').get('q'); // "a+b" (literal plus)
If you have a whole URL, let the URL object split it first, then read .searchParams:
const url = new URL('https://example.com/search?q=hello&page=2');
url.searchParams.get('q'); // "hello"
url.pathname; // "/search"
Want to see this visually? Paste any URL into our query string parser or URL parser to see every parameter decoded in a table.
Written and maintained by the urlencodedecode.com team. Every technical claim on this page is verified against primary sources — the RFCs (3986, 3629, 4648, 7578), the WHATWG URL Standard, and official vendor or language documentation — rather than second-hand summaries. When a source contradicts a common assumption, we follow the source and note the discrepancy. Corrections: contactus@urlencodedecode.com.
Use the built-in URLSearchParams: new URLSearchParams(location.search). Call .get(key) for a single value, .getAll(key) for repeated keys, and iterate with for...of to read every pair. Values are decoded automatically.
Use params.getAll('tag'), which returns an array of all values ["a","b"]. The plain params.get('tag') returns only the first value, and Object.fromEntries collapses duplicates to the last value.
In a query string, + is the form-encoded representation of a space (application/x-www-form-urlencoded), and URLSearchParams decodes it to a space. If you need a literal plus in a value, it must be encoded as %2B.
Yes. URLSearchParams is a global in modern Node.js (and available via the 'url' module in older versions), so the same code works server-side without any dependency.
Object.fromEntries(new URLSearchParams(str)) gives a plain object for unique keys. For query strings with repeated keys, loop with for...of and group the values into arrays yourself, since Object.fromEntries keeps only the last value per key.