URL Encoding Explained: encodeURIComponent vs encodeURI
URL encoding is one of those things that's easy to get wrong — and when you do, you get mysterious 400 Bad Request errors or mangled query strings. This guide covers everything you need to know.
Quick tool: URL Encoder/Decoder — encode or decode URLs instantly in your browser.
What Is URL Encoding?
URLs can only contain a limited set of safe ASCII characters. Any other characters — spaces, Chinese characters, special symbols — must be "percent-encoded" using the format %XX where XX is the hex code of the character:
Space → %20
& → %26
= → %3D
# → %23
/ → %2F
So hello world becomes hello%20world in a URL.
The Two JavaScript Functions
encodeURIComponent() — For parameter values
Encodes everything except: A-Z a-z 0-9 - _ . ! ~ * ' ( )
encodeURIComponent('hello world') // 'hello%20world'
encodeURIComponent('a & b = c') // 'a%20%26%20b%20%3D%20c'
encodeURIComponent('https://example.com') // 'https%3A%2F%2Fexample.com'
encodeURI() — For complete URLs
Preserves URL structure characters: ; , / ? : @ & = + $ #
encodeURI('https://example.com/search?q=hello world')
// 'https://example.com/search?q=hello%20world'
// Note: only the space was encoded, not ? or =
The Rule of Thumb
Use
encodeURIComponentfor values,encodeURIfor complete URLs.
// WRONG — encodeURI won't encode & and = inside the value
const badUrl = 'https://api.com?' + encodeURI('key=a&b=c');
// 'https://api.com?key=a&b=c' ← & and = are preserved, breaks param parsing
// RIGHT — encodeURIComponent encodes everything
const goodUrl = `https://api.com?q=${encodeURIComponent('a & b')}`;
// 'https://api.com?q=a%20%26%20b' ✓
Building Query Strings Correctly
Manual approach
const params = {
q: 'hello world',
lang: 'en',
source: 'https://example.com'
};
const queryString = Object.entries(params)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&');
// q=hello%20world&lang=en&source=https%3A%2F%2Fexample.com
Using URLSearchParams (recommended)
const params = new URLSearchParams({
q: 'hello world',
lang: 'en',
source: 'https://example.com'
});
const url = `https://api.example.com/search?${params}`;
// https://api.example.com/search?q=hello+world&lang=en&source=https%3A%2F%2Fexample.com
Note:
URLSearchParamsuses+for spaces (form-encoding), whileencodeURIComponentuses%20. Both are valid but inconsistent — be aware when mixing them.
Decoding query strings
const url = new URL('https://example.com/search?q=hello%20world&lang=en');
const query = url.searchParams.get('q'); // 'hello world' (auto-decoded)
// Or manually:
const encoded = 'hello%20world%20%26%20more';
console.log(decodeURIComponent(encoded)); // 'hello world & more'
Common Mistakes
Double-encoding
const value = 'hello world';
// Encoding once: hello%20world ✓
const once = encodeURIComponent(value);
// Encoding twice: hello%2520world ✗
// %20 itself gets encoded → %2520
const twice = encodeURIComponent(encodeURIComponent(value));
To fix double-encoding, decode first, then encode:
function safeEncode(str) {
// Decode if already encoded, then encode cleanly
try {
return encodeURIComponent(decodeURIComponent(str));
} catch {
return encodeURIComponent(str);
}
}
Using + for spaces vs %20
// application/x-www-form-urlencoded (HTML forms)
'hello world' → 'hello+world'
// RFC 3986 percent-encoding (most APIs)
'hello world' → 'hello%20world'
// When decoding form data on the server:
decodeURIComponent('hello+world') // 'hello+world' ← + not decoded!
decodeURIComponent('hello+world'.replace(/\+/g, ' ')) // 'hello world' ✓
Server-Side Encoding (Node.js)
const { URL, URLSearchParams } = require('url');
// Building URLs safely
const apiUrl = new URL('https://api.example.com/search');
apiUrl.searchParams.set('q', 'hello world & more');
apiUrl.searchParams.set('page', '1');
console.log(apiUrl.toString());
// https://api.example.com/search?q=hello+world+%26+more&page=1
// Express.js — query params are auto-decoded
app.get('/search', (req, res) => {
const query = req.query.q; // Already decoded by Express
// 'hello world & more'
});
Quick Reference: What Gets Encoded?
| Character | encodeURI |
encodeURIComponent |
|---|---|---|
| Space | %20 |
%20 |
/ |
(preserved) | %2F |
? |
(preserved) | %3F |
& |
(preserved) | %26 |
= |
(preserved) | %3D |
# |
(preserved) | %23 |
@ |
(preserved) | %40 |
+ |
(preserved) | %2B |
Summary
- Use
encodeURIComponentfor values inside URLs (query params, path segments) - Use
encodeURIfor complete URLs when you want to preserve structure - Prefer
URLSearchParamsfor building query strings - Prefer
new URL()for parsing and reading URL components - Watch out for
+vs%20when mixing form-encoding and percent-encoding - Never double-encode — decode first if you're unsure
For quick encoding/decoding: URL Encoder/Decoder Online
Top comments (0)