By Docify

WHATWG new URL vs encodeURI: Punycode vs Percent-Encoding

• 6 min read

WHATWG new URL() parses a URL into components and applies UTS #46 ToASCII to a special-URL host. encodeURI percent-encodes UTF-8 on the whole string and leaves reserved URI characters intact. The sample on /url-parser/ fills https://user:pass@example.com:8080/docs?q=hello world#intro. Parse writes the href https://user:pass@example.com:8080/docs?q=hello%20world#intro. The sample on /url-encoder/ fills https://example.com/search?q=hello world&category=news and output Encode URI is https://example.com/search?q=hello%20world&category=news. Host output of https://bücher.de/ is hostname xn--bcher-kva.de on /url-parser/ and https://b%C3%BCcher.de/ under encodeURI. Neither page is encodeURIComponent or a DNS lookup.

Parsing is not percent-encoding. The WHATWG URL Standard splits a string and normalizes a special-URL host with IDNA. encodeURI is an ECMA-262 encoder that never looks at scheme or host. This page names those outputs on the live URL parser and URL encoder. It is not encodeURIComponent and not URLSearchParams.

Components versus one string

new URL() versus encodeURI

Parse on /url-parser/ runs new URL(input) or new URL(input, base). That is the WHATWG URL Standard parser. It writes href, origin, protocol, username, password, host, hostname, port, pathname, search, hash, and decoded searchParams. It does not call encodeURI on the whole string. Encode URI on /url-encoder/ runs encodeURI(input). Reserved URI characters such as :/?#&=+ stay intact. A query space is %20 on both pages, not +.

new URL https://bücher.de/ → xn--bcher-kva.de · encodeURI → https://b%C3%BCcher.de/

Host, default port, and a relative path

the parsed href of https://user:pass@example.com:8080/docs?q=hello world#intro is https://user:pass@example.com:8080/docs?q=hello%20world#intro as parsed.txt. encodeURI of that same string is the same href — the only non-reserved character that needed encoding is the query space. Host output of https://bücher.de/ is hostname xn--bcher-kva.de and href https://xn--bcher-kva.de/ on /url-parser/. encodeURI output is https://b%C3%BCcher.de/. Default-port output of https://example.com:443/docs is https://example.com/docs on /url-parser/ and stays https://example.com:443/docs under encodeURI. Relative output of /docs plus https://example.com is https://example.com/docs. encodeURI of /docs stays /docs. Without a base, new URL('/docs') throws.

Only the parser host normalizes first

NFC é and NFD e + U+0301

Host of NFC é and of NFD e + U+0301 as a label produces the same xn--9ca.example on /url-parser/ because UTS #46 runs NFC first. encodeURI output of https://é.example/ is https://%C3%A9.example/. encodeURI output of the NFD host is https://e%CC%81.example/. Path output of NFC é is /%C3%A9 on both pages. Path output of NFD e + U+0301 is /e%CC%81. The path is not NFC’d first. Decode of %C3%A9 writes NFC é. Try it with the ASCII parser URL or search URL. UAX #15 output e + U+0301 → é (U+00E9) as normalized.txt lives on /unicode-normalize/.

Not encodeURIComponent and not a fetch

Sibling serializers stay on their own pages

Encode component on /url-encoder/ is encodeURIComponent. Form-urlencoded pairs are /url-search-params/ (space → +). RFC 3492 without a URL split is /punycode/. UTS #46 on a host string, not a full URL, is /idna/. Download on /url-parser/ is parsed.txt as text/plain. Neither page fetches the URL.

Parse or percent-encode the same string

WHATWG new URL() or encodeURI in the browser. Nothing is uploaded.

FAQ

What is the difference between new URL() and encodeURI?
new URL() parses and validates URLs. encodeURI only percent-encodes special characters.
Which should I use?
Use new URL() when you need to parse or build URLs. Use encodeURI for simple encoding.
Does new URL() encode automatically?
Yes. new URL() handles encoding when you set searchParams or pathname properties.
Does this tool upload my data?
No. All processing runs in your browser using JavaScript. Nothing is sent to a server.

Related