What does %5B and %5D in POST requests stand for?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
%5B and %5D are URL-encoded representations of [ (left bracket) and ] (right bracket). You will see them in POST request bodies, query strings, and browser DevTools whenever an application transmits array or nested data through HTTP. They exist because brackets are reserved characters that cannot appear raw in URLs or application/x-www-form-urlencoded payloads.
How URL Encoding Works
URL encoding (also called percent encoding) replaces every unsafe or reserved character with a % sign followed by two hexadecimal digits representing the character's ASCII code.
| Character | ASCII (decimal) | Hex | URL-Encoded |
[ | 91 | 5B | %5B |
] | 93 | 5D | %5D |
| space | 32 | 20 | %20 or + |
@ | 64 | 40 | %40 |
# | 35 | 23 | %23 |
Characters that are safe in URLs (letters, digits, -, _, .) pass through unchanged. Everything else gets encoded.
Encoding and decoding in code
JavaScript
Python
PHP
Where %5B and %5D Appear in Practice
Query strings (GET requests)
When a URL needs to carry an array, the brackets get encoded:
The server decodes this to:
Form submissions (POST requests)
Consider an HTML form with checkbox inputs that share an array-style name:
When the user checks all three and submits, the browser sends this POST body:
Nested parameters
Frameworks like Rails and Laravel use bracket notation for nested objects:
Decoded, the server interprets this as:
Which maps to the object:
How Different Frameworks Parse %5B%5D
The way a server treats bracket-encoded parameters depends on the backend framework:
| Framework | Array syntax | Nested syntax | Auto-decode |
| PHP | items[] | user[address][city] | Yes |
| Rails (Ruby) | items[] | user[address][city] | Yes |
| Express (Node) | items[] (with qs) | user[address][city] (with qs) | Yes |
| Django (Python) | items (repeated key) | Not natively supported | Partial |
| Spring (Java) | items (repeated key) | user.address.city (dot notation) | Partial |
Django and Spring do not use bracket syntax by default. In Django, you retrieve repeated keys with request.GET.getlist("items"). In Spring, you use dot notation or bind to a POJO.
Sending Arrays with fetch and axios
When you build requests from JavaScript, the encoding usually happens automatically, but it helps to know how.
fetch with URLSearchParams
axios with qs
Sending JSON instead
If your API accepts JSON, you can skip bracket encoding entirely:
JSON payloads are not URL-encoded, so brackets never appear as %5B%5D.
Common Pitfalls
- Double encoding. If you manually encode a value that the HTTP client encodes again, you end up with
%255Binstead of%5B. Let your library handle encoding, or encode only once. - Missing brackets in Django. Django does not parse
items[]into a list automatically. Userequest.POST.getlist("items[]")or drop the brackets and callrequest.POST.getlist("items"). - Framework mismatch. Sending
items[0]=a&items[1]=b(indexed brackets) works in PHP/Rails but not in Express without theqslibrary. Match your client encoding to your server framework. - Forgetting to decode for logging. Raw
%5B%5Din logs is hard to read. Run values throughdecodeURIComponent(JS) orunquote(Python) before logging. - Brackets in JSON bodies. If your Content-Type is
application/json, do not URL-encode. Brackets inside JSON are literal array delimiters and must not be percent-encoded.
Summary
%5Bis the URL-encoded form of[and%5Dis the URL-encoded form of].- They appear whenever array or nested parameters are transmitted through URL-encoded HTTP requests (both GET and POST).
- Bracket notation is the standard way PHP, Rails, and Express (with
qs) handle array parameters. - Django and Spring use repeated keys or dot notation instead of brackets.
- Sending data as JSON avoids URL encoding entirely and is generally simpler for complex structures.
- Always let your HTTP client or framework handle encoding to avoid double-encoding bugs.

