JSON to Query String Converter
Turn a flat JSON object into a URL query string.
Building query strings from JSON
A query string passes key/value data in a URL after the ?. This tool turns a flat JSON object into one, URL-encoding every key and value with the browser's form encoding, so a space becomes + and an ampersand or equals sign inside a value cannot start a new parameter. Array values are repeated as multiple parameters (e.g. tags=new&tags=sale), numbers and booleans become text, and a null or an empty array is left out, with a note saying so. A query string cannot nest, so a nested object is refused with its key named, rather than sent as [object Object]. It's handy for assembling UTM links and API requests. Everything is encoded locally in your browser.
Built and maintained by Meet Shah · Last updated
What this tool is used for
- Turning an object into the query string a GET endpoint expects.
- Building a URL by hand for a curl command from a structured payload.
- Converting a request body into parameters when moving from POST to GET.
- Producing a tracking URL from a set of parameters.
- Checking how your values will look once encoded.
How it works in practice
A worked example
A front-end developer has a shoe shop's search filters as a JSON object and needs them as the query string for the catalogue API's GET endpoint, including a return path that carries a query of its own.
{
"q": "trail shoes & socks",
"size": [9, 9.5],
"in_stock": true,
"sort": null,
"max_price": 120.00,
"return_to": "/cart?step=2"
}?q=trail+shoes+%26+socks&size=9&size=9.5&in_stock=true&max_price=120&return_to=%2Fcart%3Fstep%3D2
The parameters came out in the same order as the keys in the JSON. The ampersand in the search text came out as %26, which is what keeps socks inside q instead of starting a parameter of its own, and the slash, question mark and equals sign in the return path were percent-encoded as well, because the converter builds the string with URLSearchParams, whose form encoding leaves only ASCII letters, digits, hyphens, full stops, underscores and asterisks alone. The same encoding turned each space into a plus sign rather than %20, which means a real plus sign in a value goes out as %2B. The null sort key was dropped, the size array became the key repeated once per value, and 120.00 became 120, because the JSON is parsed into numbers first and a number keeps no record of how many decimal places it was typed with.
The edge case that catches people
The size array went out as the bare key repeated, size=9&size=9.5, and what the server makes of that depends on its parser. Node's built-in querystring module, which Express 5's default query parser is based on, returns an array for two values but a plain string for one, so the same field changes type on the day a shopper picks a single size, and the qs library behind Express 4's default parser does the same. PHP keeps only the last value of a repeated plain name, so $_GET['size'] would hold 9.5 alone. Naming the JSON key size[] produces size%5B%5D=9&size%5B%5D=9.5 instead, which PHP and qs both decode and read as a list even when it holds one value, although Node's querystring keeps size[] as a literal key name.
When not to use this tool
Do not use it to build a query string that will be signed, such as the canonical query of an AWS Signature Version 4 request or the parameters of an OAuth 1.0 signature. Both schemes percent-encode everything except ASCII letters, digits, hyphens, full stops, underscores and tildes, so a space must be %20 rather than a plus sign, a tilde stays as it is and an asterisk becomes %2A, and both sort the parameters by name before signing. This converter differs on every one of those points: it writes spaces as plus signs, turns a tilde into %7E, leaves an asterisk alone and keeps the JSON's key order, apart from keys that look like array indices, such as 2 and 10, which JavaScript lists first in ascending order. Once a value contains one of those characters or the keys are out of order, a signature calculated over its output will not match the one the service calculates.
Frequently Asked Questions
- How are nested objects handled?
- The converter refuses them and names the key, because a query string is flat and has no standard way to nest. Flatten the data first, into keys such as
filter[color]orfilter.color, whichever your server reads, or send it as a JSON body. The same goes for an object or a list inside a list. - What gets percent-encoded?
- Everything except ASCII letters, digits and
*,-,.and_, because the converter uses the browser's form encoding. A space becomes+, so a real plus sign goes out as%2B, and&,=and#are encoded too, which is what stops one value's text from silently starting a new parameter. - Is there a length limit?
- Not in the spec, but there is in practice. Browsers stop around 2,000 characters reliably, and servers impose their own limits — nginx defaults to 8 KB for the whole request line. Past a few hundred characters, use POST with a body.
- How are arrays encoded?
- As the key repeated once per value:
tag=a&tag=b. Servers read that differently: PHP keeps only the last value, and Node's querystring gives a string for one value but an array for two. Name the JSON keytag[]if the server is PHP or uses qs, which then always read a list. An empty array sends nothing. - Are numbers and booleans preserved?
- No — everything becomes text, because a query string has no types.
{"count": 5}and{"count": "5"}produce identical output, and the receiver has to coerce. A number is also written the way JavaScript prints it, so1.50goes out as1.5; quote it to keep it as typed. - Which array encoding should I use?
- Whichever the server's parser expects, since none is standard. This tool repeats the key,
a=1&a=2; naming the JSON keya[]gives PHP's form; and an API that splits on commas needs the string "1,2", which goes out asa=1%2C2and is decoded back. Guessing wrong is how a list arrives as one string.
Common errors and gotchas
- Not encoding values, so an ampersand or a space in a value breaks the whole string.
- Assuming nested objects have a standard representation, since bracket notation is a convention rather than a rule.
- Producing a URL longer than a server or a proxy will accept.
- Putting sensitive values in a query string, which is logged, cached and sent as a referrer.
- Losing type information, since every query value arrives as a string at the other end.