URL encoding explained: why spaces become %20 and when you need it
A URL can only safely contain a limited set of characters. Everything else, spaces, accented letters, slashes that are data rather than path separators, has to be percent-encoded: replaced with a % followed by the byte's hex value. A space becomes %20, an ampersand becomes %26. Knowing the rules stops a recurring family of bugs in query strings, redirects, and API calls.
Why encoding exists
URLs have structure. The ? starts the query string, & separates parameters, = joins keys to values, # starts the fragment, / separates path segments. If your actual data contains one of those characters, the parser cannot tell your data from the structure. Encoding the data first removes the ambiguity: an encoded %26 is unmistakably the literal character "&" and not a parameter separator. Encode and decode either direction with the URL Encoder / Decoder.
Reserved versus unreserved
The spec splits characters into groups. Unreserved characters, the letters, digits, and - . _ ~, never need encoding. Reserved characters have meaning in a URL and must be encoded when they appear as data rather than structure. Everything else, including spaces and most non-ASCII, is always encoded. Non-ASCII is first turned into UTF-8 bytes, then each byte is percent-encoded, which is why an emoji expands into several %xx pairs.
encodeURI versus encodeURIComponent
This is the distinction that trips people up in JavaScript:
encodeURIComponentencodes almost everything, including/,?,&, and=. Use it for a single piece of data you are dropping into a URL, like one query parameter value.encodeURIleaves the structural characters alone because it assumes you are encoding a whole URL. Use it only when you have a complete URL that just needs its spaces and unsafe characters cleaned up.
The common bug is using encodeURI on a value that contains a & or =. Those survive un-encoded and the receiving server reads your one value as several parameters. When in doubt for a single value, reach for encodeURIComponent.
Practical cases
- Building query strings by hand: encode each value with component encoding before joining with
&. Better still, letURLSearchParamsdo it. - Redirect parameters: a
?next=value that is itself a URL must be fully component-encoded, or its own query string leaks into the outer one. - Reading logs: a string full of
%20and%3Ais just an encoded URL. Paste it into the URL Encoder / Decoder to read it.
Encoding and Base64 are often confused because both produce odd-looking strings, but they solve different problems: encoding makes data safe for a URL, Base64 makes binary safe for text. If that line is fuzzy, Base64 is not encryption clears it up, and the Base64 tool handles the other case.