Every developer building URLs from user input eventually meets percent-encoding: spaces become %20, ampersands become %26, and so on. JavaScript gives you two built-in functions for this — encodeURIComponent and encodeURI — and mixing them up is one of the most common sources of broken links and double-encoded query strings. Let's sort it out.
What URL encoding actually does
URLs may only contain a limited set of characters. Everything else must be percent-encoded: replaced with % followed by its UTF-8 byte values in hexadecimal. For example:
- a space becomes
%20 -
&becomes%26 -
?becomes%3F -
ébecomes%C3%A9
JavaScript performs this for you with two global functions.
encodeURIComponent — for a single piece of a URL
encodeURIComponent() escapes everything except A-Z a-z 0-9 - _ . ! ~ * ' ( ). It's designed for encoding one value — a query parameter, a path segment, a fragment — before you drop it into a URL:
const search = "hello world & goodbye";
const url = `https://example.com/search?q=${encodeURIComponent(search)}`;
console.log(url);
// https://example.com/search?q=hello%20world%20%26%20goodbye
Note how the & inside the value is encoded to %26, so it can't be mistaken for a parameter separator.
encodeURI — for a whole URL
encodeURI() is meant for encoding an entire URI. It leaves the reserved characters that give a URL its structure untouched — ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) # — and only encodes things like spaces and non-ASCII characters:
encodeURI("https://example.com/a b?x=1&y=2");
// "https://example.com/a%20b?x=1&y=2"
The space is fixed, but ?, &, and = keep working as URL syntax.
The rule of thumb
| Situation | Use |
|---|---|
| Encoding one query parameter or path segment | encodeURIComponent |
| Encoding a full URL that already has structure | encodeURI |
| Decoding them back |
decodeURIComponent / decodeURI
|
The classic mistake is encoding a whole URL with encodeURIComponent:
encodeURIComponent("https://example.com/?q=a b");
// "https%3A%2F%2Fexample.com%2F%3Fq%3Da%20b" — broken!
The : and / characters are structural — encoding them destroys the URL.
Beware double encoding
Encoding an already-encoded string produces garbage: %20 becomes %2520. This usually happens when a value passes through two layers (e.g., your code encodes it and the HTTP library encodes it again). The fix is to encode exactly once, at the boundary where you assemble the URL.
The modern alternative: URLSearchParams
For query strings, the URLSearchParams API handles encoding for you and is usually the cleanest choice:
const params = new URLSearchParams({ q: "hello world", tag: "a&b" });
console.log(params.toString());
// "q=hello+world&tag=a%26b"
One quirk to know: URLSearchParams encodes spaces as + (the application/x-www-form-urlencoded convention), while encodeURIComponent produces %20. Both are valid in query strings, and servers decode either form. decodeURIComponent does not turn + back into a space, though — so pair it with encodeURIComponent output, not with form-encoded strings.
When you'd rather not write code
If you just need to encode or decode a string quickly, the free URL encoder/decoder on Toolstack does it instantly in your browser — no signup, everything runs client-side so your data never leaves your device. Useful for one-off fixes like an API key with special characters in a query string.
Takeaways
-
encodeURIComponentis for individual values;encodeURIis for whole URLs. - Never encode a full URL with
encodeURIComponent— it will escape the:and/that hold the URL together. - Encode exactly once to avoid double encoding (
%2520). - For query strings, consider
URLSearchParams, which encodes for you. - For quick one-offs, a free online URL encoder/decoder gets it done without any setup.
Top comments (0)