Article · Mar 3, 2026 · 5 min read

encodeURI vs encodeURIComponent

JavaScript has two URL encoding functions: encodeURI and encodeURIComponent. They look interchangeable, they have nearly identical names, and they produce different output. Most JavaScript URL bugs trace back to using the wrong one of these two.

This article explains the difference, when to use each, and the rare cases where encodeURI is actually correct.

The short version

Use encodeURIComponent for individual parts of a URL — query parameter values, path segments, hash fragments. It encodes everything that could possibly be a special character.

Use encodeURI only when you have a complete URL where you want to preserve reserved characters (:, /, ?, &, =, #) literal. In practice, this is almost never what you want.

If you can’t articulate why you specifically need encodeURI, you want encodeURIComponent.

What each one does

encodeURIComponent: encodes more

encodeURIComponent encodes everything except:

A-Z   a-z   0-9   -   _   .   !   ~   *   '   (   )

That’s the unreserved set plus a few legacy characters. Everything else — including : / ? # [ ] @ & = + $ , — gets percent-encoded.

encodeURIComponent("https://example.com/search?q=hello world&lang=en")
// "https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Dhello%20world%26lang%3Den"

encodeURI: encodes less

encodeURI leaves the structural URL characters alone in addition to the unreserved set:

; / ? : @ & = + $ , #

The rationale: these are the characters URL parsers use to split a URL into structural components. encodeURI assumes the input is a complete URL where these characters are syntax, not data.

encodeURI("https://example.com/search?q=hello world&lang=en")
// "https://example.com/search?q=hello%20world&lang=en"

Notice: the colons, slashes, ?, and & stay literal. Only the space got encoded.

When encodeURI is actually correct

The textbook case for encodeURI: you have a complete URL where:

  1. Every :, /, ?, & is structural (part of the URL syntax)
  2. You need to encode characters that violate URL syntax (spaces, non-ASCII)
  3. You haven’t pre-encoded the parts

Example: rendering a URL that came from user input where they typed accented characters:

const userTypedUrl = "https://example.com/café/menu";
const cleaned = encodeURI(userTypedUrl);
// "https://example.com/caf%C3%A9/menu"
// Now valid URL syntax

In real production code, this is rare. You usually know exactly which part of the URL is data and which is structure, so you reach for encodeURIComponent on the data parts and assemble the URL manually.

When encodeURIComponent is correct (almost always)

You have a value that’s going to be inserted into a URL. The value is data, not URL structure. Maybe it contains & or = or ? — and if those characters are interpreted as URL structure, your URL breaks.

// User search query
const q = "rock & roll";
const url = `/search?q=${encodeURIComponent(q)}`;
// "/search?q=rock%20%26%20roll"
// Server reads q="rock & roll"

// Without the encoding:
const url = `/search?q=${q}`;
// "/search?q=rock & roll"
// Server reads q="rock " and a separate parameter "roll"

The textbook mistake

// Wrong — encoding a whole URL with encodeURIComponent
const baseUrl = "https://api.example.com/search";
const url = encodeURIComponent(`${baseUrl}?q=${query}`);
// "https%3A%2F%2Fapi.example.com%2Fsearch%3Fq%3D..."
// → This is no longer a URL. It’s an encoded blob.

The fix: encode the data parts only:

const url = `${baseUrl}?q=${encodeURIComponent(query)}`;
// "https://api.example.com/search?q=encoded-query-value"

The other textbook mistake

// Wrong — using encodeURI on a value that contains a query separator
const userInput = "C&C games";
const url = `/search?q=${encodeURI(userInput)}`;
// "/search?q=C&C games"     ← encodeURI left the & alone!
// Server reads q="C", C games="" — two parameters

// Right — use encodeURIComponent for values
const url = `/search?q=${encodeURIComponent(userInput)}`;
// "/search?q=C%26C%20games"

This is the most common mistake. encodeURI looks like the “safer” encoder because of the name, but it leaves the reserved characters alone — which is exactly the problem when those characters are inside your data.

The modern alternative: URL and URLSearchParams

For 99% of cases, the right answer in modern JavaScript is to skip encodeURI / encodeURIComponent entirely and use the URL constructor:

// Building a URL
const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "rock & roll");
url.searchParams.set("lang", "en");
console.log(url.toString());
// "https://api.example.com/search?q=rock+%26+roll&lang=en"

// Parsing a URL
const url = new URL("https://example.com/search?q=rock%20%26%20roll");
console.log(url.searchParams.get("q"));
// "rock & roll"

URL + URLSearchParams handle encoding automatically and correctly for each URL part. You can’t accidentally encode a structural character or forget to encode a data character.

Decision tree

You have a string to put in a URL. Which encoder?

  1. Are you building a URL with structured data? → Use new URL() + URLSearchParams. Don’t use either encode function.
  2. Are you encoding a single value (query param value, path segment, fragment)? → encodeURIComponent
  3. Do you have a complete URL with reserved characters that should stay literal? → encodeURI
  4. Are you sure? → No. Use encodeURIComponent.

Quick reference: which characters each function encodes

Character encodeURI encodeURIComponent
space%20%20
: / ? # & =literal%XX
+ ; , $ @literal%XX
! ~ * ' ( )literalliteral
é (Unicode)%C3%A9%C3%A9

For complete predictability, use encodeURIComponent on data parts and assemble URLs yourself — or better yet, use the modern URL / URLSearchParams APIs.


Found this useful? Try the URL decoder, the URL encoder, or browse all tools.

More reading

From the blog.