JavaScript's URL Encoding Functions
If you’ve ever worked with URLs in JavaScript, you’ve probably come across two oddly similar functions:
encodeURIComponent()
and encodeURI()
. At first glance, they look like they’re
doing the same job—but they’re not. Each serves a slightly different purpose, and using the wrong one can
quietly break your app in ways that are tricky to debug.
Let’s break them down and figure out when to use which.
encodeURIComponent() vs encodeURI(): What’s the Difference?
encodeURIComponent()
This one’s the stricter sibling. encodeURIComponent()
encodes pretty much everything except a
handful of safe characters:
A-Z a-z 0-9 - _ . ! ~ * ' ( )
Because it’s so thorough, you’ll want to use it for individual parts of a URL—things like
query parameters or path segments. Basically, anywhere a stray &
or =
could
cause chaos.
// Example: encodeURIComponent()
const param = "hello world & special=chars";
const encoded = encodeURIComponent(param);
console.log(encoded);
// Output: "hello%20world%20%26%20special%3Dchars"
encodeURI()
encodeURI()
, on the other hand, is more forgiving. It leaves characters like ?
,
&
, =
, and #
alone because those symbols are essential for
structuring a full URL. Here’s the list of what it keeps intact:
A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #
This function shines when you need to encode an entire URL but still want it to work as a proper address.
// Example: encodeURI()
const url = "https://example.com/hello world?param=value&other=special chars";
const encodedUrl = encodeURI(url);
console.log(encodedUrl);
// Output: "https://example.com/hello%20world?param=value&other=special%20chars"
When to Use Which
Use encodeURIComponent()
when encoding:
- Query parameter values (and names)
- Fragment identifiers
- Path segments
- Any string that’s just a piece of the URL
// Correct usage: encoding query parameters
const baseUrl = "https://example.com/search";
const query = "javascript & web development";
const category = "programming/how-to";
const url = `${baseUrl}?q=${encodeURIComponent(query)}&cat=${encodeURIComponent(category)}`;
console.log(url);
// Output: "https://example.com/search?q=javascript%20%26%20web%20development&cat=programming%2Fhow-to"
Use encodeURI()
when encoding:
- A full URL you don’t want to break
- URLs with spaces in paths
- Situations where query separators (&, =, ?) must remain untouched
// Correct usage: encoding a complete URL with spaces
const path = "https://example.com/my page.html";
const encodedPath = encodeURI(path);
console.log(encodedPath);
// Output: "https://example.com/my%20page.html"
Warning: Don’t use encodeURI()
for query parameters—it won’t encode
critical characters like &
, =
, or ?
. That’s a recipe for broken
URLs.
Decoding: The Other Half of the Story
Of course, what you encode you’ll eventually need to decode. JavaScript gives you two matching functions:
decodeURIComponent()
– for strings encoded withencodeURIComponent()
decodeURI()
– for strings encoded withencodeURI()
// Encoding and decoding
const original = "hello world & special=chars";
// Encode
const encoded = encodeURIComponent(original);
console.log(encoded); // "hello%20world%20%26%20special%3Dchars"
// Decode
const decoded = decodeURIComponent(encoded);
console.log(decoded); // "hello world & special=chars"
Note: Always decode with the matching function. Mixing them up can lead to half-decoded messes.
Common Mistakes (and How to Dodge Them)
1. Using the wrong function for query parameters
// ❌ Wrong
const baseUrl = "https://example.com/search";
const query = "value with & and =";
const badUrl = `${baseUrl}?q=${encodeURI(query)}`;
// Breaks: & and = stay unencoded
// ✅ Correct
const goodUrl = `${baseUrl}?q=${encodeURIComponent(query)}`;
2. Double encoding
// ❌ Wrong
const text = "hello world";
const doubleEncoded = encodeURIComponent(encodeURIComponent(text));
// "hello%2520world"
// ✅ Correct
const singleEncoded = encodeURIComponent(text);
// "hello%20world"
3. Ignoring errors while decoding
// ❌ Wrong
decodeURIComponent("%E0%A4%A"); // Throws an error
// ✅ Correct
function safeDecodeURIComponent(encoded) {
try {
return decodeURIComponent(encoded);
} catch (e) {
console.warn("Failed to decode:", encoded);
return encoded;
}
}
Going a Step Further
Custom encoding for special cases
// Custom encode
function customEncode(str) {
let encoded = encodeURIComponent(str);
encoded = encoded.replace(/%20/g, '+'); // Spaces to +
encoded = encoded.replace(/%2B/g, '+'); // Preserve +
return encoded;
}
// Custom decode
function customDecode(encoded) {
encoded = encoded.replace(/\+/g, '%20');
return decodeURIComponent(encoded);
}
Handling Unicode gracefully
const unicodeText = "café résumé";
const encodedUnicode = encodeURIComponent(unicodeText);
console.log(encodedUnicode); // "caf%C3%A9%20r%C3%A9sum%C3%A9"
const decodedUnicode = decodeURIComponent(encodedUnicode);
console.log(decodedUnicode); // "café résumé"
Browser Support
Good news: every modern browser supports these functions, and they’ve been around since the very first
version of ECMAScript back in 1997. The only gotcha? Invalid sequences. Newer browsers will throw an error,
while older ones might behave unpredictably. When in doubt, wrap decoding in try...catch
.
Real-World Examples
Building a URL with parameters
function buildUrl(baseUrl, params) {
const queryString = Object.keys(params)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&');
return `${baseUrl}?${queryString}`;
}
const params = {
q: "javascript tutorial",
page: "1",
sort: "relevance",
category: "web development"
};
console.log(buildUrl("https://example.com/search", params));
Parsing query parameters
function parseQueryParams(url) {
const queryString = url.split('?')[1];
if (!queryString) return {};
return queryString.split('&').reduce((params, pair) => {
const [key, value] = pair.split('=').map(decodeURIComponent);
params[key] = value;
return params;
}, {});
}
const testUrl = "https://example.com/search?q=javascript%20tutorial&page=1";
console.log(parseQueryParams(testUrl));
// {q: "javascript tutorial", page: "1"}