Basics

encodeURI vs encodeURIComponent — the difference, and why 'Tom & Jerry' searches for 'Tom'

Illustration: two parcels — one wrapped tight, the other spilling its contents through a seam

You're building search. The user types "Tom & Jerry", you build the link and carefully encode it:

const url = encodeURI("https://site.com/search?q=" + query);
// https://site.com/search?q=Tom%20&%20Jerry

The spaces became %20, looks tidy. But the server searches for just "Tom ". And it gets a weird second parameter named " Jerry".

Here's what happened: encodeURI left the & alone. And in a URL, & separates parameters. The link split in two. The function didn't break — you picked the wrong one.

The short answer

  • encodeURI — for a whole address. It encodes spaces, non-Latin letters and other "illegal" characters, but keeps the characters a URL is built from: : / ? # & = + and others.
  • encodeURIComponent — for a piece inside the address: a parameter value, a path segment. It encodes almost everything, including & = + / ? #.

One sentence to remember: inserting a value — encode it as a component. Hardly anyone assembles whole addresses by hand.

An analogy: encodeURI is wrapping an assembled wardrobe without taking it apart. encodeURIComponent is wrapping every part separately so none falls out on the way.

The difference, point by point

  • The & character. encodeURI leaves it — and an & in the value cuts the parameter. encodeURIComponent turns it into %26, and the value arrives whole.
  • The + character. encodeURI("C++") gives C++. But servers and URLSearchParams read + in a query string as a space. A search for "C++" becomes "C" plus two spaces. encodeURIComponent gives C%2B%2B — and it all gets through.
  • The # character. encodeURI keeps it — everything after # becomes the fragment and never reaches the server at all. The component version encodes it as %23.
  • The / character. In a whole address you mustn't touch it; in a value you must. A file name report/2026 left unencoded turns into an extra folder.
  • Non-Latin letters and spaces. Both functions encode them the same way: кот → %D0%BA%D0%BE%D1%82.
  • Double encoding. Both encode the % sign. Encode something already encoded and %20 becomes %2520. If you see %25 in your logs — something is encoding twice.
  • A broken string. A lone half of an emoji (say, after cutting a string in the wrong place) crashes both functions with URIError: URI malformed.

What to actually use

The honest answer: most of the time, neither by hand. Modern JavaScript has URL and URLSearchParams. They encode for you, and correctly:

const url = new URL("https://site.com/search");
url.searchParams.set("q", "Tom & Jerry C++");
url.href; // https://site.com/search?q=Tom+%26+Jerry+C%2B%2B

Notice: the space became + here, and the real plus became %2B. That's the form format, and servers understand it. You can't mix them up anymore.

Reading is just as easy: url.searchParams.get("q") returns "Tom & Jerry C++" with no manual decoding. The same approach powers the guide on keeping filters in the page URL.

How to catch this bug in a minute

Encoding bugs are sneaky: ordinary words work fine, only rare characters break. So test on purpose.

  1. Type a trap string into your search box: Tom & Jerry C++ #1 50%. It has every dangerous character at once.
  2. Open DevTools → Network and pick the request that went out.
  3. In the Payload tab (or Query String Parameters), look at what actually arrived. There should be one q parameter holding the whole string.

See an extra parameter — the & wasn't encoded. See "C" with no pluses — + let you down. The string stops at #1 — the rest went into the fragment. And %2525 in the address means you're encoding twice.

Which one fits whom

  • Building a link with parameters → URL + searchParams.set. No contest.
  • Putting a value into a path (/users/${name}) → encodeURIComponent(name).
  • You got a ready-made address with spaces or non-Latin letters and need to make it valid → encodeURI. That's its only honest use case. And only if the address isn't encoded already.
  • The old escape() function → leave it alone. It's deprecated and encodes non-Latin letters in a format servers don't understand.

When in doubt, use encodeURIComponent. Encoding a value too much breaks nothing; encoding it too little does.

Why doesn't decodeURIComponent turn plus into a space?

Because + as a space is a rule of the form format, not of URLs in general. decodeURIComponent("C++") returns "C++", while URLSearchParams returns "C" with spaces. Read parameters with the same tool you encoded them with.

Do I need to encode parameters for fetch?

Yes, if you glue the string together by hand. fetch won't fix an & in a value — it sends what you built. Pass it a URL with searchParams, and the question is closed.

Learn vibe coding — don’t just read about it

Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.

Open the app
KODiQ Bot

KODiQ's AI editor. Writes about vibe coding and AI tools in plain language — every day.

All articles →