URLSearchParams: Repeated Keys, Ordering, and Form Encoding
See how repeated values, append/set, and plus-versus-space encoding behave, then test the exact contract your server expects.
Publication & corrections: infostoa · Editorial standards
Individual author and specialist reviewer information is not provided for this article.
URLSearchParams represents query data as an ordered list of name-value pairs, not as a single-value object. That distinction matters when an API accepts repeated keys such as filters. The WHATWG URL Standard defines getAll() as returning matching values in list order; the MDN API guide illustrates the methods developers use to preserve or replace those pairs.
A metaphor of keys and shapes passing through a machine; it does not show ordered name=value pairs or actual URLSearchParams serialization.
Read, append, or replace repeated values
This query contains two tag pairs. get() returns the first matching value, while getAll() returns both in order. append() keeps existing pairs and adds another at the end. set() replaces the matching name with one value and removes its other occurrences.
const params = new URLSearchParams("tag=blue&tag=green");
params.get("tag"); // "blue"
params.getAll("tag"); // ["blue", "green"]
params.append("tag", "red");
params.set("tag", "gold"); // only tag=gold remains
Use append() when a multi-select filter should remain a list, and set() when a setting is meant to have one current value. Then verify the server framework’s behavior: duplicate fields may be parsed as an array, the first value, or the last value. The browser API does not define that server-side contract.
A plus sign is not always a plus sign
When the string constructor parses q=a+b, form-style parsing treats + as a space, so the value becomes a b. When you add the value a+b with append(), the plus is literal data and serializes as %2B. Form serialization may represent a space as +. Keep the original spelling, the parsed value, and the newly serialized query distinct when exact bytes matter.
new URLSearchParams("q=a+b").get("q"); // "a b"
const p = new URLSearchParams();
p.append("q", "a+b");
p.toString(); // "q=a%2Bb"
The constructor is not a full-URL parser. To parse an address, pass its query component, for example new URL(location.href).searchParams or new URLSearchParams(location.search).
Test the API boundary, not just the browser object
Suppose a user selects tag=blue and tag=green. Test that the outgoing request contains both pairs, that the server receives them in the intended order, and that an empty value is distinguishable from a missing key. If those expectations differ, agree on the API contract or change the parser.
Equivalent logical values can have different raw query strings after encoding or URL serialization. If raw bytes feed a signature, cache key, or exact log comparison, define ordering, duplicate handling, empty values, and canonicalization first. URLSearchParams handles query encoding; it is not an input sanitizer and does not provide authentication or authorization.