URL encoding vs Base64
URL encoding and Base64 are both encoding schemes — ways to represent data as text that’s safe to transmit through systems with restrictions. But they target different problems, have very different size characteristics, and you generally use them for different things.
This article compares them on every dimension that matters.
What each one is for
URL encoding targets the URL/URI character set. It percent-encodes anything that’s not in the unreserved set. Designed for embedding arbitrary text within URLs.
Base64 targets binary data. It uses 64 ASCII characters (A-Z, a-z, 0-9, +, /) to represent any byte sequence in a way that’s safe through email, JSON, XML, and HTTP without binary-encoding issues. Designed for transmitting binary blobs as text.
Size: Base64 wins, by a lot
URL encoding has variable inflation depending on the input. For ASCII text with mostly unreserved characters, the overhead is near zero. But for binary data or non-ASCII text:
Each non-unreserved byte becomes 3 characters (%XX). For binary data where most bytes need encoding, that’s a 3× inflation.
Base64 turns 3 bytes into 4 characters. For any data — text or binary — that’s a 33% inflation (4/3 ≈ 1.33×).
| Input | Size | URL-encoded | Base64 |
|---|---|---|---|
| ASCII text "Hello" | 5 B | 5 chars (0%) | 8 chars (+60%) |
| UTF-8 "café" | 5 B | 9 chars (+80%) | 8 chars (+60%) |
| 1 KB binary | 1024 B | ~3072 chars (+200%) | 1368 chars (+33%) |
| 10 KB binary | 10240 B | ~30720 chars (+200%) | 13680 chars (+33%) |
For binary data, Base64 is dramatically more compact. For ASCII text, URL encoding can be smaller (often zero overhead). For UTF-8 text, they’re comparable.
Reversibility
Both are perfectly reversible. Neither is encryption — anyone can decode the output without a key. Both preserve every byte of the original.
Character set comparison
URL encoding output: letters, digits, -, _, ., ~, and %XX sequences. About 70 distinct characters appear in output (when input has variety).
Base64 output: letters, digits, +, /, and optionally = padding. Exactly 65 distinct characters possible.
Both produce ASCII output, so both can travel through systems that require ASCII.
URL safety
Here’s the twist: standard Base64 is NOT URL-safe. The + and / characters have URL-reserved meanings. To use Base64 in a URL, you need Base64URL — a variant that replaces + with - and / with _, and (usually) drops the = padding:
// Standard Base64
btoa("Hello, World!"); // "SGVsbG8sIFdvcmxkIQ=="
// Base64URL (URL-safe variant)
btoa("Hello, World!")
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, ''); // "SGVsbG8sIFdvcmxkIQ"
// URL encoded
encodeURIComponent("Hello, World!"); // "Hello%2C%20World!"
Base64URL is what JWT tokens use, what cryptography APIs produce, and what URL-aware Base64 implementations output by default.
When to use URL encoding
Use URL encoding when:
- You’re putting plain text or short strings into URLs (search queries, IDs, names)
- You want the output to remain human-readable (mostly)
- The data is already mostly URL-safe ASCII
- You need maximum compatibility — every URL parser understands it
When to use Base64 / Base64URL
Use Base64 when:
- The data is binary (images, encrypted blobs, hashes, cryptographic keys)
- The data is large enough that the 3× URL-encoding overhead matters
- You’re embedding the data in JSON, XML, email headers, or other ASCII-required contexts
- You need stable size scaling — Base64 is always 33% inflation regardless of input
The combined approach (rare but real)
Sometimes you Base64-encode binary data, then URL-encode the result to put it in a URL:
const binaryData = new Uint8Array([0xFF, 0xD8, 0xFF, /* JPEG bytes */]);
const base64 = btoa(String.fromCharCode(...binaryData));
const urlSafe = encodeURIComponent(base64);
const url = `https://api.example.com/upload?data=${urlSafe}`;
This works but is inefficient — you have two layers of encoding overhead. Better: use Base64URL directly (no second encoding pass needed) or send binary as a POST body instead of a URL parameter.
Real-world examples
JWT (JSON Web Token)
// JWT = base64url(header) + "." + base64url(payload) + "." + base64url(signature)
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.signature_here
JWTs use Base64URL because they need to be URL-safe (passed as query params, embedded in URLs) but contain binary signature data.
Data URIs
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...">
Embedding image data in HTML uses Base64 for the size advantage. URL encoding would 3× the size.
Search query in URL
?q=Hello%2C%20World%21
Plain text in URLs uses percent-encoding for readability and minimum overhead.
OAuth access tokens
?access_token=mF_9.B5f-4.1JqM
OAuth tokens are designed to be URL-safe (using only unreserved characters plus -, ., _, ~), so neither encoding is needed.
Bottom line
| Use case | Pick |
|---|---|
| Text in a URL | URL encoding |
| Binary in a URL | Base64URL |
| Binary in JSON / XML / email | Base64 |
| Embedding an image inline | Base64 (data URI) |
| JWT token | Base64URL (by spec) |
For more on Base64 specifically, try our sister site base64decode.tools — same philosophy as this site, but for Base64.
Found this useful? Try the URL decoder, the URL encoder, or browse all tools.