TechCompare LogoTechCompare

Which characters need percent-encoding in URLs? Reserved vs unreserved explained

Use a library or built-in function (encodeURIComponent, URLSearchParams, Python's urllib.parse.urlencode) rather than manually deciding which characters to encode. The spec is subtle, the bugs are silent, and the libraries are correct.

RFC 3986 divides URL characters into three sets: unreserved (always safe, never encode), reserved (have special meaning, encode when used as data), and everything else (always encode). Knowing which set a character belongs to is the difference between a URL that works and one that silently breaks in production.

By TechCompare · Updated

Encoding focus
Percent-encoding deep dive
percent-encoding
Category
Best Practices
Practical encoding guidance

How this is calculated

Unreserved characters: A-Z, a-z, 0-9, hyphen (-), underscore (_), period (.), tilde (~). These never need encoding. Reserved characters are split into gen-delims (: / ? # [ ] @) and sub-delims (! $ & ' ( ) * + , ; =). Reserved characters should be percent-encoded when they appear in a URL component where they don't serve their delimiter role. An & in a query parameter value must be encoded as %26. An & separating two query parameters must remain literal. This context sensitivity is why you should use a proper URL builder or encodeURIComponent() rather than regex-replacing characters.

Verdict

RFC 3986 splits URL characters into unreserved (A-Z, a-z, 0-9, hyphen, underscore, period, tilde), reserved gen-delims, and reserved sub-delims. The trap is context: an ampersand separating two query params stays literal, but the same ampersand inside a value must become %26. That's why hand-rolled regex replacement breaks and the built-in helpers (encodeURIComponent, URLSearchParams, urllib.parse.urlencode) don't.

More Encoding scenarios

Base64 vs Hex
Base64 and hexadecimal both encode binary data as text, but they serve different purposes.
View details ➜
UTF-8 vs ASCII
ASCII maps 128 English characters to 7-bit values.
View details ➜
URL encoding guide
Percent-encoding (also called URL encoding) replaces characters that aren't safe in a URL with a percent sign followed by two hex digits.
View details ➜

Frequently asked questions

Which characters never need percent-encoding in a URL?
The unreserved set from RFC 3986: A-Z, a-z, 0-9, hyphen, underscore, period, and tilde. These are safe in every part of a URL, from domain to path to query value. Every other character either carries structural meaning or must be encoded as data.
When does an ampersand need to be %26 in a URL?
When it's data, not structure. An ampersand separating two query parameters stays literal, but an ampersand inside a value (like a search for 'fish & chips') must encode to %26, or the server reads a parameter boundary that isn't there. That context sensitivity is exactly why hand-rolled find-and-replace breaks and proper encoders don't.
Should I encode URLs with a regex or a library?
A library, always. encodeURIComponent in JavaScript, URLSearchParams, or Python's urllib.parse.urlencode all encode correctly per component. The reserved character rules differ between path, query, and fragment segments, so a regex that works on one URL shape silently corrupts another. The bugs are invisible until a user hits an edge case in production.