Toolcedar

encodeURI or encodeURIComponent? One Rule That Works

The two differ by eleven characters, and picking wrong either breaks the URL or corrupts the value. Here is the rule, and the plus-sign trap.

· 3 min read

A URL is not a string; it is a structure. Slashes separate path segments, a question mark starts the query, an ampersand separates parameters, and a hash begins the fragment. Percent-encoding exists so that a value can contain one of those characters without being mistaken for the structure. The two encoding functions differ on exactly one question: are you encoding the structure, or something going inside it?

The rule

Use encodeURIComponent for a piece that goes into a URL, and encodeURI for a whole URL that is already assembled. In practice you almost always want the first one, because the second is only correct in a narrow case: you have a complete, structurally valid URL containing illegal characters — a space in a path, say — and you want it made legal without disturbing the structure.

The difference is that encodeURI deliberately leaves the reserved characters alone, because in a whole URL they are doing their job. encodeURIComponent escapes them, because in a value they are not.

const value = 'a/b?c=d&e';

encodeURI(value);           // 'a/b?c=d&e'      unchanged, still structural
encodeURIComponent(value);  // 'a%2Fb%3Fc%3Dd%26e'  safe inside a parameter

What goes wrong with the wrong one

Encoding a value with encodeURI is the more damaging mistake, and the one that survives testing. A search term containing an ampersand passes straight through, and the server reads everything after it as a separate parameter. Your search for "salt & pepper" arrives as a search for "salt" plus an unexpected parameter named "pepper". Nothing errors; the result is simply wrong.

The opposite mistake is louder and therefore safer. Running encodeURIComponent over a whole URL escapes the slashes and the colon, producing a string no browser will treat as a link at all. That fails immediately and gets fixed immediately.

The plus sign

Percent-encoding writes a space as %20. HTML form submission uses an older convention in which a space is a plus sign. Both turn up in real query strings, sometimes in the same application, and neither decoder handles the other automatically.

The consequence is that decoding a form-encoded value with a plain URI decoder leaves literal plus signs sitting in your data, and encoding a genuine plus sign — in a phone number, or in an email address using tagged addressing — without escaping it produces a space on arrival. If a value can contain a plus, it must be encoded as %2B, and that is what encodeURIComponent does.

A plus in a query string is ambiguous by history. Encode it as %2B and the ambiguity disappears.

Double encoding

Encoding an already-encoded string escapes the percent signs themselves, so %20 becomes %2520. This usually happens when a value is encoded on the way into a template and again on the way out, or when a redirect URL is passed through two layers that each try to be helpful. The symptom is unmistakable once you know it: %25 appearing where you expected nothing, and literal percent sequences showing up in the rendered page. Decode once and check before deciding it is corrupt — often the value is fine and simply encoded twice.

What is never encoded

  • The unreserved set — letters, digits, hyphen, underscore, period and tilde — is safe everywhere and left untouched by both functions.
  • encodeURI additionally preserves the reserved set, including : / ? # [ ] @ ! $ & ' ( ) * + , ; =
  • encodeURIComponent preserves only the unreserved set plus ! ' ( ) * , which is why it is the right choice for values.

One last note on the fragment. Everything after the hash never reaches the server; it is handled entirely by the browser. That makes it a poor place for anything sensitive and a common source of confusion when a value seems to vanish server-side. It is not being stripped — it was never sent.

Frequently asked questions

Which one should I use to build a query string?
encodeURIComponent, applied separately to each key and each value, then joined with the ampersands and equals signs yourself. Encoding the assembled string instead would escape the separators you just added.
Why does my space become a plus sign instead of %20?
Because something in the chain used HTML form encoding rather than percent-encoding. Both conventions are in active use for query strings. Decode with the same convention that produced the value, or normalise plus signs to spaces before decoding.
Is a percent-encoded URL longer in a way that hurts SEO?
Length itself is not a ranking factor, but unreadable URLs are worse for click-through in results and for anyone copying a link. Prefer readable slugs so the path needs no encoding at all.