How to Encode URLs in JavaScript: encodeURI vs encodeURIComponent

Try the URL Encoder

JavaScript's Four URL Encoding Functions

JavaScript provides four built-in functions for URL encoding and decoding: encodeURI(), encodeURIComponent(), decodeURI(), and decodeURIComponent(). Each serves a distinct purpose, and choosing the wrong one is one of the most common sources of URL-related bugs in JavaScript applications. The fundamental distinction is this: encodeURI() is designed for encoding complete URLs, so it leaves structural URL characters (like /, ?, #, and &) untouched. encodeURIComponent() encodes everything that isn't an unreserved character, making it the right choice for encoding individual query parameter names and values. Understanding when to use each function — and knowing about the older deprecated alternatives that still haunt legacy codebases — will save you from subtle, hard-to-debug data corruption issues.

encodeURI(): For Complete URLs

encodeURI() encodes a string as a complete URI, preserving all characters that have structural meaning in URLs. It does not encode: letters (A–Z, a–z), digits (0–9), the unreserved symbols (- _ . ~), and the reserved characters that serve structural roles in URLs: ; , / ? : @ & = + $ # and ! ' ( ) *. It does encode: spaces, non-ASCII characters, and characters like % (when not followed by a valid hex pair), [, ], ^, `, and { | }. Example usage: encodeURI("https://example.com/search?q=hello world&lang=en") produces "https://example.com/search?q=hello%20world&lang=en" — the space is encoded but ?, &, and = remain intact because they're part of the URL structure. Use encodeURI() when you have a complete URL that might contain spaces or non-ASCII characters but is otherwise structurally correct.

encodeURIComponent(): For Query Parameter Values

encodeURIComponent() is the workhorse of URL encoding in JavaScript. It encodes every character except the unreserved set: letters, digits, -, _, ., and ~. This means it does encode &, =, ?, /, #, +, :, @, and all other special characters. This aggressive encoding is exactly what you want when encoding individual parameter values, because a raw & or = in a value would break the query string parser. Here's the critical pattern for building query strings correctly:

// WRONG - breaks if values contain & or =
const url = `https://api.example.com/search?q=${query}&category=${cat}`;

// CORRECT - always encode each value
const url = `https://api.example.com/search?q=${encodeURIComponent(query)}&category=${encodeURIComponent(cat)}`;

// Better: use URLSearchParams (see below)
const params = new URLSearchParams({ q: query, category: cat });
const url = `https://api.example.com/search?${params.toString()}`;

Never trust that user input, database values, or external API responses won't contain URL-breaking characters. Always encode values with encodeURIComponent() before embedding them in URLs.

decodeURI() and decodeURIComponent()

The decode counterparts reverse the encoding process. decodeURI() decodes a string that was encoded with encodeURI() — it does not decode sequences that represent characters with structural URL meaning (it won't decode %2F back to /, for instance, because that could change the URL's path structure). decodeURIComponent() decodes everything, including those structural characters — use this when you've extracted a query parameter value and want to recover the original string. In modern JavaScript (and TypeScript), you'll often use these in combination with URLSearchParams: const params = new URLSearchParams(window.location.search); automatically handles decoding for you when you call params.get('q'). For manual decoding, always catch URIError exceptions — if the input contains a malformed percent sequence (like %GG or a lone %), the decode functions will throw rather than silently ignore the bad data.

The URLSearchParams API: The Modern Approach

Since ES2015+, the URLSearchParams interface provides a clean, bug-resistant way to work with query strings. It handles encoding and decoding automatically, letting you focus on the data rather than the encoding mechanics:

// Building a query string
const params = new URLSearchParams();
params.append('q', 'rock & roll');
params.append('artist', 'AC/DC');
params.append('year', '2024');
console.log(params.toString());
// q=rock+%26+roll&artist=AC%2FDC&year=2024

// Parsing a query string
const search = '?name=John+Doe&city=New%20York';
const parsed = new URLSearchParams(search);
console.log(parsed.get('name')); // "John Doe"
console.log(parsed.get('city')); // "New York"

// Iterating all parameters
for (const [key, value] of parsed) {
    console.log(`${key}: ${value}`);
}

Note that URLSearchParams uses + to encode spaces (the application/x-www-form-urlencoded style) rather than %20. Both are valid for query strings, but be aware of this when interoperating with systems that use one or the other.

The URL API: Parsing and Constructing URLs Safely

The URL constructor (also available in Node.js since v7.0.0) is the most robust way to work with URLs in JavaScript. It validates URLs, handles relative URLs, and provides clean access to URL components:

// Parsing a URL
const url = new URL('https://example.com/path?q=hello+world#section');
console.log(url.pathname);  // "/path"
console.log(url.search);    // "?q=hello+world"
console.log(url.hash);      // "#section"
console.log(url.searchParams.get('q')); // "hello world" (decoded!)

// Constructing a URL with dynamic parts
const base = new URL('https://api.example.com');
base.pathname = '/users/' + userId; // Set path safely
base.searchParams.set('filter', 'active & verified');
base.searchParams.set('page', '1');
console.log(base.toString());
// https://api.example.com/users/123?filter=active+%26+verified&page=1

The URL API is available in all modern browsers and Node.js. It's the safest way to construct URLs programmatically because it handles encoding automatically, validates the URL structure, and prevents many common encoding bugs.

Deprecated: escape() and unescape()

You may encounter escape() and unescape() in older JavaScript code. These functions are deprecated and should never be used for URL encoding. The escape() function was designed before Unicode was fully understood: it encodes non-ASCII characters as %uXXXX (a non-standard format) for characters above U+00FF, and it doesn't encode the + sign. This makes it incompatible with the percent-encoding standard defined in RFC 3986 and produces URLs that many servers won't correctly parse. Additionally, escape() doesn't encode the @, *, /, and + characters, which can cause subtle bugs. Always replace escape() with encodeURIComponent() and unescape() with decodeURIComponent(). If you're maintaining legacy code, this substitution is usually a safe drop-in replacement.

Practical Cheat Sheet: Which Function to Use?

Here's a quick decision guide for URL encoding in JavaScript. Use encodeURIComponent() when: encoding a query parameter name, encoding a query parameter value, encoding a URL that will itself be embedded as a parameter in another URL, or encoding any user-supplied input that goes into a URL. Use encodeURI() when: you have a full URL that might have non-ASCII characters or spaces but is otherwise structurally sound, and you want to make it safe without altering its structure. Use URLSearchParams when: building or parsing query strings in modern JavaScript or Node.js. Use the URL constructor when: parsing a URL into its components or constructing a URL from parts programmatically. Never use escape()/unescape() for URL encoding — only for legacy compatibility with code that already uses them. Never manually replace characters with a lookup table — the built-in functions handle Unicode and edge cases correctly. Our online URL encoder tool applies the same RFC 3986 standard these functions use — try it to verify your encoding expectations.

Encode URLs Instantly

Encode and decode URLs with full Unicode support, multiple encoding modes, and batch processing.

Open URL Encoder