🔀

Base64 vs URL encoding: what's the difference?

Two encoding schemes that sound similar and are constantly confused. Here's what each one does, where they're used, and why you shouldn't mix them up.

· 5min read

“Base64 encoding” and “URL encoding” sound like they should do similar things — they both convert data into a different representation using only safe characters. But they solve different problems, produce very different output, and are used in different places. Confusing the two is a reliable way to break APIs, mangle links, and lose hours to debugging.

The two encodings at a glance

Base64URL encoding (percent-encoding)
PurposeRepresent binary data as textMake strings safe for URLs
Alphabet64 characters (A-Z, a-z, 0-9, +, /)Any printable ASCII, uses %XX for unsafe characters
Size increaseExactly +33%Variable (typically +0-200% depending on content)
Used inEmail, JSON, data URIs, JWTsURLs, form submissions, query strings
InputBytesText (usually a string that contains special characters)

What URL encoding actually does

URL encoding (formally percent-encoding, defined in RFC 3986) is the scheme that lets you put arbitrary text into a URL without breaking it.

URLs have structure:

https://example.com/search?q=coffee&lang=en

Certain characters have special meaning: ? separates the path from the query string, & separates query parameters, = separates key from value, / separates path segments, # starts the fragment. If you want to include any of those characters as data — say, a query for “A & B” — you need to escape them so the URL parser doesn’t get confused. URL encoding does this by replacing each special character with % followed by its two-digit hexadecimal ASCII code:

  • Space → %20 (or sometimes + in query strings)
  • &%26
  • =%3D
  • #%23

So A & B becomes A%20%26%20B (or A+%26+B in a query string).

URL encoding only touches the characters that need escaping; safe characters (letters, digits, -, _, ., ~) pass through untouched. For input that’s already mostly safe characters, the output is only slightly longer. For input full of special characters — quotes, slashes, non-ASCII — it can be much longer.

What Base64 actually does

Base64 is completely different. It takes bytes (not necessarily text) and produces text that uses only the 64 characters in its alphabet. Every 3 bytes of input becomes 4 characters of output, always.

Base64 doesn’t care what the input is. It treats everything as bytes and outputs a string that’s safe to put almost anywhere text is expected. The output is exactly 33% longer than the input (plus padding to the nearest 4 characters with =).

Base64 is the go-to when you need to put binary data — a PNG image, a zip file, an encrypted blob — through a text-only channel like email or JSON. URL encoding can’t really do that. It’s designed for text-to-text transformation, not arbitrary binary.

The overlap: when you need both

There’s one specific scenario where both encodings show up: putting binary data in a URL.

Say you have a tiny image (20 bytes of PNG) and you want to embed it in a URL as a parameter. First, Base64-encode the image — you get a 28-character string. Then URL-encode that Base64 string, because the +, /, and = characters in Base64 output all have special meanings in URLs and become %2B, %2F, %3D.

Because this combination is so common, a variant called Base64 URL-safe exists. It uses - and _ instead of + and / (which are safe in URLs without escaping), and typically drops the = padding:

  • Standard Base64: a+b/c=
  • URL-safe Base64: a-b_c

JWTs (JSON Web Tokens) use URL-safe Base64, which is why you see strings like eyJhbGciOiJIUzI1NiJ9 without any + or / characters.

Side-by-side example

Input: the text Hello, world! (13 bytes)

URL encoding (treats the whole thing as text, escapes the comma, space, and !):

Hello%2C%20world%21

Length: 19 characters. Still readable.

Base64 encoding (treats the 13 bytes and converts to text):

SGVsbG8sIHdvcmxkIQ==

Length: 20 characters. Not readable.

URL-safe Base64 (Base64 without characters that need escaping):

SGVsbG8sIHdvcmxkIQ

Length: 18 characters. Used in JWTs and compact IDs.

When to use URL encoding

Reach for URL encoding when you’re embedding user input in a URL path or query string — anything a human types into a search box needs URL encoding before it becomes part of a URL. HTML forms submit data in URL-encoded form by default, so that’s handled for you. Same goes for building REST API URLs that include dynamic parameters like usernames, IDs with special characters, or file paths.

Don’t use URL encoding for binary data. It doesn’t handle arbitrary bytes well, and anything beyond ASCII becomes awkward and wastes space on % escapes. For files and images, Base64 first.

When to use Base64

Reach for Base64 when you’re transmitting binary data through a text-only channel (JSON, email, XML), when you’re embedding small files in HTML or CSS via data URIs, or when you’re working with tokens and certificates that come as bytes but need to be stored as text.

Don’t reach for Base64 when the data is already text and you just need to escape special characters for a URL — that’s URL encoding’s job. And if size matters and you have a binary-safe channel, just send the bytes directly instead of inflating them by 33%.

Common mix-up scenarios

”I Base64-encoded a string to put it in a URL, and it’s still broken”

Base64 output contains +, /, and = — all of which have special meaning in URLs. You either need to URL-encode the Base64 string, or use the URL-safe Base64 variant (which uses - and _ instead).

”I URL-encoded a file but it’s corrupted”

URL encoding treats input as text, which means non-ASCII bytes are handled inconsistently depending on the encoding assumed. For binary files, you need Base64 first, then URL-encode the result if necessary.

”The API says to Base64-encode the password for Basic Auth”

HTTP Basic Authentication takes username:password, Base64-encodes that whole string, and puts it in the Authorization header. This is not because Base64 is secure — it isn’t. It’s because the header needs to survive transmission through systems that might mangle raw text with colons and special characters. The security comes from HTTPS, not from Base64.

A practical workflow

The Base64 tool handles encoding and decoding cleanly: paste text in to get Base64 out, paste Base64 in to get text out, or upload a file to get Base64 out. For URL encoding specifically, every language has a one-liner:

  • JavaScript: encodeURIComponent(str) / decodeURIComponent(str)
  • Python: urllib.parse.quote(str) / urllib.parse.unquote(str)
  • PHP: urlencode($str) / urldecode($str)
  • Ruby: CGI.escape(str) / CGI.unescape(str)

For combined scenarios — binary data in a URL — the standard pattern is: Base64 first, then URL-encode if needed (or use URL-safe Base64 directly).


The rule of thumb that actually sticks: URL encoding is for text-to-URL, Base64 is for bytes-to-text. Use URL encoding for URL construction. Use Base64 for binary-in-text. Use both together when you need binary data inside a URL. Once that clicks, the confusion tends to go away.