Stop Parsing URLs With String Tricks
Before the URL API existed, people sliced URLs with split('?'), regexes, and hope. It mostly worked until a value contained an &, a =, a space, or a non-ASCII character — and then it didn't. The browser and Node both ship a proper parser. Use it.
One call, every part of the URL already split apart and decoded correctly. The constructor throws a TypeError on invalid input, which is usually what you want — a garbage URL should fail loudly rather than silently produce garbage downstream.
Reading Query Parameters
Every URL has a .searchParams property — a URLSearchParams object that knows how to read and write the query string:
A few things worth noticing:
- Values come back already decoded.
?name=Ada%20Lovelacegives you"Ada Lovelace". - Everything is a string.
"2"is not2. Convert withNumber()if you need a number. - Repeated keys are legal.
getreturns the first match;getAllreturns every match. - Missing keys return
null, notundefined— so?? "default"works well with them.
Building a Query String
You can build a query string from scratch with URLSearchParams — no manual escaping, no joining with &:
Or construct it from an object — any iterable of [key, value] pairs works, and a plain object does too:
set vs append: set replaces any existing value for that key. append adds another one. Use append when a key can legitimately repeat (tags, filters); use set for single-valued parameters.
Modifying a URL
Because URL is a live object, changing searchParams updates .search and .href automatically:
This is the idiomatic way to append a query parameter to an existing URL. No "does the URL already have a ?" check, no worrying about whether to prepend & or ?.
You can change other parts of the URL the same way:
Iterating Over Parameters
URLSearchParams is iterable. for...of gives you [key, value] pairs, and there are the usual keys(), values(), and entries() helpers:
Note that repeated keys show up multiple times — you'll see tag = web and then tag = beginner as separate entries. That's faithful to the actual query string.
If you want a plain object for a quick debug print, Object.fromEntries works — but it collapses repeats, keeping only the last value:
Fine for debugging. Wrong if any key can repeat.
Relative URLs Need a Base
new URL("/search?q=js") on its own throws — a relative path isn't a valid URL by itself. Pass a base as the second argument:
The resolution rules are the same ones browsers use for <a href>: a leading / is absolute from the host, no slash is relative to the current path, .. walks up. Very handy when you're assembling API URLs from a configured base.
In the browser, window.location.href is a ready-made base for parsing the current page's URL:
const u = new URL(window.location.href);
const page = u.searchParams.get("page") ?? "1";
Handling Invalid URLs
The URL constructor throws on malformed input. That's useful — but it means you need try/catch when parsing anything the user typed or an external system sent:
Modern environments also expose URL.canParse(input) — a boolean check that avoids the try/catch dance when you just want to validate:
A Small Working Example
Putting it together — read the current filters from a URL, tweak them, and produce a new URL to navigate to:
Passing null deletes the parameter. Any other value sets or overwrites it. That's a pattern you'll end up writing in one form or another any time you build filter UIs, pagination, or deep links.
What to Take Away
new URL(string)parses a URL into labelled parts. It throws on garbage.url.searchParamsis aURLSearchParams— useget,getAll,set,append,delete,has.- Encoding happens for you. Don't reach for
encodeURIComponentunless you're building strings by hand. - Pass a base URL as the second argument to resolve relative paths.
URL.canParse(ortry/catch) is your validation tool for untrusted input.
Every time you're tempted to split a URL with .split('?') or pick a query parameter out with a regex, reach for these APIs instead. They're shorter, correct, and already in the runtime.
Frequently Asked Questions
How do I parse a URL in JavaScript?
Pass the string to the URL constructor: const u = new URL('https://example.com/path?x=1'). The resulting object exposes protocol, host, pathname, search, hash, and a searchParams helper. It throws on invalid URLs, so wrap it in try/catch when parsing untrusted input.
How do I get a query string parameter in JavaScript?
Use url.searchParams.get('name'). It returns the decoded value or null if the parameter isn't present. For parameters that can repeat (?tag=a&tag=b), use searchParams.getAll('tag') to get all values as an array.
What's the difference between URL and URLSearchParams?
URL parses and represents a whole URL — protocol, host, path, query, hash. URLSearchParams is just the query-string part, and you can use it standalone to build or parse a=1&b=2 strings. Every URL instance has a .searchParams property that's a URLSearchParams tied to that URL.
Do I need to encode query parameters manually?
No. URLSearchParams encodes keys and values automatically when you call set, append, or read back the string. That handles spaces, &, =, and Unicode correctly. Only reach for encodeURIComponent when you're building a string by hand, which you usually shouldn't.