블로그로 돌아가기

Base64 vs URL Encoding: What's the Difference?

Published on June 23, 2026 · 7 min read

You paste a URL into a browser address bar — it works perfectly. The page loads, the query parameters resolve, everything renders. But try embedding that same URL inside a JSON payload or stuffing it into a JWT token claim, and suddenly things break. Characters get misinterpreted, data gets corrupted, and your carefully constructed string turns into garbage.

The reason is that Base64 encoding and URL encoding solve fundamentally different problems, even though they can look superficially similar. Both produce text output from some kind of input, and both are fully reversible. But that's where the similarity ends. URL encoding makes text safe for URLs. Base64 makes binary data safe for text-only systems. Confusing the two leads to silent data corruption, broken APIs, and debugging sessions you wouldn't wish on anyone.

In this guide, we'll walk through exactly what each encoding does, where they differ, where they overlap (and why that overlap causes confusion), and how to pick the right one for your situation. You'll come away with a clear mental model that saves you from the most common encoding mistakes.

What Is URL Encoding?

URL encoding — formally called percent-encoding— is a mechanism for representing characters in a URL that would otherwise be ambiguous or prohibited. URLs are only allowed to contain a specific set of characters: the unreserved set (A-Z, a-z, 0-9, -, _, ., ~) and a handful of reserved characters that have special meaning (like /, ?, &, =, #). Everything else must be encoded.

Percent-encoding works by replacing an unsafe character with a percent sign (%) followed by the character's two-digit hexadecimal ASCII code. For example, a space becomes%20 (ASCII 32 in hex is 20), and an ampersand becomes %26.

Here are the most common characters that get URL-encoded and what they become:

Character  Name            Encoded
─────────  ──────────────  ──────
 space     Space           %20
 !         Exclamation     %21
 "         Double quote    %22
 #         Hash            %23
 $         Dollar          %24
 %         Percent         %25
 &         Ampersand       %26
 '         Single quote    %27
 (         Left paren      %28
 )         Right paren     %29
 *         Asterisk        %2A
 +         Plus            %2B
 ,         Comma           %2C
 /         Forward slash   %2F
 :         Colon           %3A
 ;         Semicolon       %3B
 =         Equals          %3D
 ?         Question mark   %3F
 @         At sign         %40
 [         Left bracket    %5B
 ]         Right bracket   %5D

A real-world example makes this concrete. The string Hello World! contains a space and an exclamation mark, both of which need encoding for safe URL usage:

Input:  Hello World!
Output: Hello%20World%21

// Space (ASCII 32 = 0x20) → %20
// Exclamation (ASCII 33 = 0x21) → %21

URL encoding is used everywhere in web development: query strings (?q=hello%20world), form submissions with application/x-www-form-urlencoded, path segments containing special characters, and fragment identifiers. Whenever the browser sends a request with special characters in the URL, it automatically percent-encodes them behind the scenes.

The key thing to understand: URL encoding operates on text strings. Its job is to take any text and make it safe for transport inside a URL by escaping characters that have special meaning in the URL syntax.

What Is Base64 Encoding?

Base64 encoding solves a completely different problem. It's a binary-to-text encoding designed to represent arbitrary binary data using only printable ASCII characters. The name comes from the 64-character alphabet it uses: uppercase letters (A-Z, 26 chars), lowercase letters (a-z, 26 chars), digits (0-9, 10 chars), plus+ and / (2 chars), totaling 64 characters. The = character is used for padding when the input length isn't evenly divisible by 3.

Under the hood, Base64 takes blocks of 3 bytes (24 bits) and splits them into 4 groups of 6 bits. Each 6-bit value (0-63) maps to one character in the Base64 alphabet. This produces output that's roughly 33% larger than the input — a predictable and constant expansion ratio.

// Binary data → Base64
Input bytes:  "Man" (3 bytes = 24 bits)
Binary:       01001101 01100001 01101110
Split 6-bit:  010011 010110 000101 101110
Decimal:      19     22     5      46
Base64 chars: T      W      F      u
Output:       "TWFu"

// The formula: 3 bytes → 4 Base64 characters
// Output is always 4/3 (133%) the size of input

Base64 shows up everywhere you need to move binary data through text-based systems: data URIs for embedding images in HTML and CSS (data:image/png;base64,...), JWT tokens, email attachments (MIME), API request bodies carrying file data, and cryptographic key exchange formats. In every case, the purpose is the same: take something that isn't text and represent it as text that can safely travel through text-only channels.

The critical distinction: Base64 operates on binary data, not text. While you certainly canBase64-encode a text string (which first gets converted to bytes via a character encoding like UTF-8), the encoding itself doesn't know or care about the semantics of the input. It treats everything as raw bytes.

Core Differences

Let's lay out the differences side by side so you can see exactly where they diverge:

Property          URL Encoding              Base64 Encoding
────────────────  ────────────────────────  ─────────────────────
Purpose           Make text URL-safe        Make binary text-safe
Input type        Text strings              Binary data (bytes)
Output size       Variable (1-3x input)     Fixed 4/3x (133%)
Expansion         1 byte → 1-3 chars        3 bytes → 4 chars
Character set     % + hex digits            A-Z, a-z, 0-9, +, /, =
Reversible        Yes                       Yes
Standard          RFC 3986                  RFC 4648
Aware of content  Yes (knows URL syntax)    No (treats all as bytes)
Typical use       Query strings, forms      Data URIs, JWT, MIME

Let's dig into the most important differences in detail:

Purpose

URL encoding exists to preserve meaning in URLs. If you want to pass the literal string “fish & chips” in a query parameter, you need to encode the space and the ampersand so the URL parser doesn't interpret & as a parameter separator. URL encoding says: “Here's a character that would break your URL parser — let me represent it in a way that's safe.”

Base64 encoding exists to transport binary data through text systems. If you have an image file and need to send it in a JSON payload, you can't just paste raw bytes into JSON. Base64 says: “Here's binary data — let me represent it entirely with safe ASCII characters.”

Input Type

This is the most fundamental difference and the source of most confusion. URL encoding expects text— it needs to know what character each byte represents so it can decide whether to encode it. Base64 expects bytes— it doesn't care whether those bytes represent text, an image, or encrypted data. It encodes them all the same way.

Output Size and Predictability

URL encoding produces variable output sizes. A character that's URL-safe (likea) stays as-is (1 byte in, 1 byte out). An unsafe character (like ~) becomes 3 characters (%7E). A mostly-ASCII string with few special characters barely grows at all. A string full of spaces and symbols can triple in size.

Base64 produces perfectly predictable output: 4 output characters for every 3 input bytes (with padding for partial blocks). This 33% expansion is constant and independent of the input content. You always know exactly how large the output will be before you encode.

Character Set

URL encoding uses %plus two hex digits — a completely different alphabet from Base64. This means a URL-encoded string looks unmistakably different from a Base64-encoded string. If you see%signs followed by hex digits, that's URL encoding. If you see a mix of letters, digits,+,/, and maybe=at the end, that's Base64.

When They Overlap and Cause Confusion

The confusion between Base64 and URL encoding usually starts with JWT tokens. A typical JWT looks like this:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U

At first glance, it looks like it might be URL-encoded because it contains- and _characters — characters you rarely see in standard Base64. But this isn't URL encoding at all. It'sBase64URL encoding, a variant of Base64 designed specifically for URL contexts. The - and _ replace the URL-unsafe + and / from standard Base64.

To see just how different these encodings are, let's take the same input string and run it through both URL encoding and Base64URL encoding:

Input:                test/123?key=value

URL Encoded:          test%2F123%3Fkey%3Dvalue
Base64URL Encoded:    dGVzdC8xMjM_a2V5PXZhbHVl
Base64 (Standard):    dGVzdC8xMjM/a2V5PXZhbHVl

Notice three things: First, the URL-encoded version uses percent signs and hex digits to escape the special characters (/,?,=). Second, the Base64 versions look nothing like the URL-encoded version — every single character is different. Third, even though the Base64URL output contains? and =(from the original input being encoded), these characters are not acting as URL special characters — they simply happen to appear as part of the Base64 alphabet for this specific input.

The point: these encodings produce completely different output from the same input. They are not interchangeable. Using one where the other is expected guarantees data corruption.

Base64URL: Where Base64 Meets URLs

We touched on it above, but Base64URL deserves its own explanation because it's the bridge between these two worlds. Standard Base64 uses+ and /— two characters that have special meaning in URLs (the plus sign decodes to a space in query strings, and the forward slash is a path separator). If you embed standard Base64 directly into a URL without additional encoding, your data can get mangled.

Base64URL (defined in RFC 4648 Section 5) solves this by making two character substitutions:

  • + becomes - (hyphen)
  • / becomes _ (underscore)
  • Padding =characters are typically omitted (they're not needed for decoding when the encoded length is known)

This is still Base64— the same encoding algorithm, the same 6-bit grouping, the same mathematical foundation. The only difference is which two characters sit in positions 62 and 63 of the encoding alphabet, and whether padding is included. But those two small changes make the output safe for URLs without requiring secondary percent-encoding.

// Same binary data, three different text representations
Data:          "Hello" (5 bytes)

Standard Base64:   SGVsbG8=
Base64URL:         SGVsbG8  (no padding, but same chars here)
URL Encoded:       Hello    (all chars are URL-safe, so no encoding needed)

// A case where the difference is visible
Data bytes:        0xFB 0xFF (2 bytes of arbitrary binary)

Standard Base64:   +/8=
Base64URL:         -_8   (hyphen replaces +, underscore replaces /)
URL Encoded:       %FB%FF (makes no sense here —
                    URL encoding operates on text, not bytes)

For a deeper dive into Base64URL, check out our developer's guide to URL-safe Base64. If you need to convert between formats right now, use our Base64 URL Encoder/Decoder tool.

Practical Scenarios

Theory is helpful, but the real value comes from knowing which encoding to reach for in specific situations. Here are five common scenarios you'll encounter in web development:

Scenario 1: Sending Binary Data in a REST API

You need to include file contents in a JSON API request. JSON only supports text, so raw bytes won't work. The solution: Base64-encode the binary dataand include the resulting string in the JSON body. The receiver Base64-decodes it back to the original file. This is the standard approach used by countless APIs, including AWS S3 multipart uploads and Stripe's file upload endpoints.

// API request body (JSON)
{
  "filename": "report.pdf",
  "content": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBl...",
  "encoding": "base64"
}

Scenario 2: Building a URL Query String with Special Characters

You're building a search URL and the user typed “coffee & tea” into the search box. If you naively build/search?q=coffee & tea, the server interprets & as a query parameter separator. The solution: URL-encode the parameter value using encodeURIComponent() in JavaScript or equivalent in other languages.

// JavaScript
const query = "coffee & tea";
const url = "/search?q=" + encodeURIComponent(query);
// Result: /search?q=coffee%20%26%20tea

// The ampersand (&) becomes %26 so the parser
// knows it's literal data, not a separator

Scenario 3: Embedding an Image in HTML

You want to inline a small icon directly in your HTML instead of making a separate HTTP request. The solution: Base64-encode the image bytes and use a data URI. URL encoding plays no role here because the data URI itself uses Base64 as its encoding mechanism, not percent-encoding.

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="icon" />

// The Base64 image data goes directly in the src attribute.
// No URL encoding needed — data URIs use Base64 natively.

Scenario 4: Passing a Base64 String in a URL Parameter

This is where both encodings come into play. You have a Base64-encoded token and you need to pass it as a query parameter. Standard Base64 contains+ and /, both of which break in URLs. You have two options:

  1. Use Base64URL (the preferred approach): Encode your data using URL-safe Base64 from the start, which produces URL-friendly output without+ or /.
  2. Double-encode: If you already have standard Base64 output, URL-encode the Base64 string so + becomes %2B and / becomes %2F.
// You have a Base64 token:
const token = "dGVzdCtkYXRhL2ZpbGU=";  // standard Base64

// Option A: Convert to Base64URL (preferred)
// → "dGVzdCtkYXRhL2ZpbGU"  (replace +→-, /→_, drop =)

// Option B: URL-encode the standard Base64 string
// → "dGVzdCtkYXRhL2ZpbGU%3D"  (%2B for +, %2F for /, %3D for =)

// The receiver must decode in the right order:
// Option A: just Base64URL-decode
// Option B: URL-decode first, then Base64-decode

Scenario 5: Form Submission with Special Characters

When a user submits an HTML form, the browser automatically URL-encodes the form data (using application/x-www-form-urlencoded) before sending it to the server. You don't need to do anything — the browser handles percent-encoding form field values that contain spaces, ampersands, or other special characters. Base64 isn't involved here at all unless you explicitly encode file contents for a text-based form field.

The Double Encoding Pitfall

One of the most common and frustrating bugs is accidentally double-encoding data, especially when Base64 and URL encoding interact. Here's what happens when you URL-encode a string that's already Base64-encoded:

// Step 1: Base64-encode "Hello World"
Input:              Hello World
Base64 output:      SGVsbG8gV29ybGQh

// Step 2: Now URL-encode the Base64 string
URL-encoded Base64: SGVsbG8gV29ybGQh
//                   ^ all chars happen to be URL-safe here!

// But consider a Base64 string with = padding:
Base64:             SGVsbG8gV29ybGQhIC0g
URL-encoded:        SGVsbG8gV29ybGQhIC0g%3D
//                                        ^ = becomes %3D

Double-encoding itself isn't always wrong — it's sometimes necessary (as in Scenario 4 above). The problem arises when the receiver doesn't know to decode in the right order. If you URL-encode a Base64 string and the receiver only Base64-decodes without URL-decoding first, it'll try to Base64-decodeSGVsbG8gV29ybGQhIC0g%3D and get garbage because % isn't a valid Base64 character.

The golden rule: decoding order must be the reverse of encoding order. If you applied Base64 first, then URL encoding, the receiver must URL-decode first, then Base64-decode. Think of it like unwrapping nested packages — you open the outermost layer first.

Encoding:   Data → Base64 → URL-encode → Transport
Decoding:   Transport → URL-decode → Base64-decode → Data

// The most common mistake:
Encoding:   Data → Base64 → URL-encode → Transport
Decoding:   Transport → Base64-decode → ❌ Garbage!
//                       ^ forgot to URL-decode first!

Which One Should You Use?

Here's a straightforward decision framework for choosing the right encoding:

  • Use URL encodingwhen you're putting text into a URL path, query string, or fragment and that text contains characters with special meaning in URLs (spaces, ampersands, question marks, hashes, etc.). Think: search queries, form data, dynamic path segments.
  • Use Base64 when you need to represent binary data (files, images, cryptographic keys) in a text-only format like JSON, XML, CSV, or HTML attributes. Think: API file uploads, data URIs, email attachments.
  • Use Base64URL when you need Base64 but the result will appear in a URL context (query parameters, path segments, redirect URLs). Think: JWT tokens, OAuth state parameters, verification tokens in email links.
  • Use both togetherwhen you have standard Base64 output that must travel through a URL. First, consider converting to Base64URL instead. If that's not possible, URL-encode the Base64 string — and document the decode order clearly for the receiver.

A simple litmus test: ask yourself “Am I dealing with binary data or text with special characters?”Binary data points to Base64. Text with URL-unsafe characters points to URL encoding. If the answer is “binary data that needs to go through a URL,” the answer is Base64URL.

And if you're ever unsure, remember: they produce completely different output. A Base64-encoded string will never accidentally look like a URL-encoded string, and vice versa. If you see percent signs followed by hex digits, that's URL encoding. If you see a long string of letters, digits,+,/, and = (or - and _for the URL-safe variant), that's Base64.

Try It Yourself

The best way to internalize these differences is to see them in action. Open our text converter and type any string — maybe “Hello World!” or “test/123?key=value&foo=bar.” Then use our Base64 URL encoder to Base64-encode the same string. Compare the two outputs side by side. The URL-encoded version will selectively escape only the special characters, while the Base64 output will transform every byte into a character from the Base64 alphabet.

Try encoding a binary file next. Drop an image or a small PDF into the Base64 encoder and observe that URL encoding isn't even an option — it operates on text, not arbitrary bytes. Then try Base64URL-encoding the result: notice how the+ and / characters disappear, replaced by URL-safe alternatives. Finally, take a standard Base64 string containing+ and /and paste it into a URL as a query parameter — watch the browser automatically percent-encode those characters for you. That's both encodings working together in the wild.

Once you've seen the outputs side by side, the difference between these two encodings becomes second nature. And the next time someone asks you to “just URL-encode the file,” you'll know exactly why that doesn't make sense — and what to use instead.

Keep Reading