What are the best practices for URL encoding?
Following URL encoding best practices prevents bugs, security issues, and broken links.
1. Always Encode User Input
Never trust user input - always encode it before adding to URLs:
// Bad - vulnerable to injection
const url = `/search?q=${userInput}`;
// Good - safely encoded
const url = `/search?q=${encodeURIComponent(userInput)}`;
2. Use the Right JavaScript Function
encodeURIComponent() - For query parameters (most common):
const param = encodeURIComponent("Hello World & You!");
const url = `/api?text=${param}`;
// Result: /api?text=Hello%20World%20%26%20You%21
encodeURI() - For encoding entire URLs (preserves :/?#):
const fullUrl = encodeURI("https://example.com/path with spaces");
// Result: https://example.com/path%20with%20spaces
Don't use escape() - It's deprecated!
3. Only Encode What Needs Encoding
// Bad - over-encoding
const url = encodeURIComponent("https://example.com/api?key=value");
// Result: https%3A%2F%2Fexample.com%2Fapi%3Fkey%3Dvalue (broken URL!)
// Good - encode only the parameter value
const url = `https://example.com/api?redirect=${encodeURIComponent("https://other.com")}`;
// Result: https://example.com/api?redirect=https%3A%2F%2Fother.com
4. Avoid Double-Encoding
// Bad - encoding twice
const text = "Hello World";
const encoded = encodeURIComponent(text); // "Hello%20World"
const doubleEncoded = encodeURIComponent(encoded); // "Hello%2520World" (wrong!)
// Good - encode once
const url = `/api?text=${encodeURIComponent(text)}`;
5. Use URLSearchParams for Query Strings
Modern and automatic:
const params = new URLSearchParams({
search: "Hello World",
filter: "price>100",
category: "Books & Media"
});
const url = `/api?${params.toString()}`;
// Automatically encodes everything correctly
6. Handle Special Cases
File paths:
const filename = "my resume (final).pdf";
const path = `/files/${encodeURIComponent(filename)}`;
Email addresses:
const email = "user+tag@example.com";
const url = `/api?email=${encodeURIComponent(email)}`;
International characters:
const city = "São Paulo";
const url = `/weather?city=${encodeURIComponent(city)}`;
// Result: /weather?city=S%C3%A3o%20Paulo
7. Security Considerations
Prevent injection attacks:
// Attacker input: "; DROP TABLE users--
const malicious = ""; DROP TABLE users--";
// Bad - allows injection
const query = `SELECT * FROM items WHERE name='${malicious}'`;
// Good - but use parameterized queries in real code!
const safeValue = encodeURIComponent(malicious);
Prevent open redirects:
// Validate URLs before encoding
function safeRedirect(url) {
const allowed = ["https://mysite.com", "https://myapp.com"];
const urlObj = new URL(url);
if (!allowed.includes(urlObj.origin)) {
throw new Error("Invalid redirect");
}
return encodeURIComponent(url);
}
8. Testing
Always test with edge cases:
- Spaces:
Hello World - Special chars:
!@#$%^&*() - Reserved chars:
:/?#[]@!$&'()*+,;= - Unicode:
こんにちは,مرحبا,🎉 - Symbols:
C++,O'Brien,50%
9. Decoding
Always decode when receiving:
const params = new URLSearchParams(window.location.search);
const query = params.get("q"); // Automatically decoded
// Or manually
const encoded = new URL(window.location.href).searchParams.get("q");
const decoded = decodeURIComponent(encoded);
10. Framework Usage
Use framework utilities when available:
// React Router
<Link to={`/search?q=${encodeURIComponent(term)}`} />
// Next.js
router.push({
pathname: '/search',
query: { q: term } // Next.js handles encoding
});
// Express
res.redirect(`/search?q=${encodeURIComponent(term)}`);
Common Pitfalls to Avoid:
❌ Not encoding at all
❌ Encoding the entire URL
❌ Double-encoding
❌ Using wrong function (escape instead of encodeURIComponent)
❌ Forgetting to decode on the server
❌ Mixing URL encoding with HTML encoding
❌ Not handling UTF-8 properly
✅ Always encode user input
✅ Use encodeURIComponent for parameters
✅ Test with special characters
✅ Decode when receiving data
✅ Use modern APIs like URLSearchParams