← Back to Blog
Base64EncodingWeb Development

Base64 Encoding: What It Is and How It Works

What is Base64 Encoding?

Base64 is a binary-to-text encoding scheme that converts binary data into a string of ASCII characters. It uses a set of 64 characters — A-Z, a-z, 0-9, +, and / — plus = for padding. Every three bytes of input become four characters of output.

The name says it all: Base-64, an encoding with a 64-character alphabet.

You encounter Base64 constantly in web development, even if you don't realize it. Data URIs in HTML and CSS, email attachments (MIME), JWT tokens, API authentication headers, and embedded images all rely on Base64 encoding.

How Base64 Works

The encoding process is straightforward:

  1. Take the input bytes and concatenate their binary representations (8 bits each)
  2. Split into 6-bit groups (since 2^6 = 64, each group maps to one of 64 characters)
  3. Map each 6-bit value to a character in the Base64 alphabet
  4. Pad with = if the input length isn't a multiple of 3

Let's walk through an example. Encoding the string "Hi":

H        i
01001000 01101001          (ASCII binary)
010010 000110 1001??       (split into 6-bit groups)
010010 000110 100100       (pad last group with zeros)
S      G      k      =    (map to Base64 + padding)

So "Hi" becomes "SGk=". The = at the end indicates one byte of padding was needed.

The 3:4 ratio is why Base64 increases data size by approximately 33%. Three input bytes produce four output characters. This overhead is the main trade-off of Base64 encoding.

Common Use Cases

Data URIs

Data URIs let you embed small files directly in HTML or CSS, eliminating extra HTTP requests:

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

This is useful for small icons, SVGs, or images under a few kilobytes. For larger files, the 33% size increase makes this counterproductive — a separate file with proper caching is better.

Email Attachments (MIME)

Email was designed for ASCII text. To send binary attachments (images, PDFs, zip files), email clients encode them as Base64 within the MIME format. This is why email attachments are larger than the original files — that 33% overhead applies.

JWT Tokens

JSON Web Tokens use Base64URL encoding (a URL-safe variant using - and _ instead of + and /) for their header and payload sections:

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWxpY2UifQ.signature

Each section before and after the dots is a Base64URL-encoded JSON object. You can decode the first two parts to inspect the token's contents — which is why JWTs should never contain sensitive data unless encrypted.

API Authentication

HTTP Basic Authentication encodes credentials as Base64:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Decoding dXNlcm5hbWU6cGFzc3dvcmQ= gives you username:password. This is not encryption — it's trivially reversible. Basic Auth should only be used over HTTPS.

Embedding Binary Data in JSON

JSON doesn't support binary data natively. When you need to include binary content (like a file or image) in a JSON payload, Base64 encoding is the standard approach:

{
  "filename": "report.pdf",
  "content": "JVBERi0xLjQKMSAwIG9iago8PA..."
}

Base64 Variants

The standard Base64 alphabet isn't always suitable. Several variants exist:

  • Standard (RFC 4648): Uses A-Za-z0-9+/ with = padding. The most common variant.
  • URL-safe (Base64URL): Replaces + with - and / with _. Omits padding. Used in JWTs, URLs, and filenames.
  • MIME: Same alphabet as standard but inserts line breaks every 76 characters. Used in email.

When working with Base64, always check which variant the system expects. Mixing up standard and URL-safe encoding is a common source of bugs.

How to Encode and Decode Base64

Every language has built-in Base64 support:

JavaScript (Browser):

const encoded = btoa('Hello, world!');      // "SGVsbG8sIHdvcmxkIQ=="
const decoded = atob('SGVsbG8sIHdvcmxkIQ=='); // "Hello, world!"

JavaScript (Node.js):

const encoded = Buffer.from('Hello, world!').toString('base64');
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');

Python:

import base64
encoded = base64.b64encode(b'Hello, world!').decode()
decoded = base64.b64decode(encoded).decode()

Command line:

echo -n 'Hello, world!' | base64           # encode
echo 'SGVsbG8sIHdvcmxkIQ==' | base64 -d   # decode

For quick encoding and decoding without writing code, you can use our free Base64 tool — paste any text or Base64 string and convert instantly.

When NOT to Use Base64

Base64 is often misused. Here are cases where it's the wrong choice:

Don't use it for security. Base64 is encoding, not encryption. Anyone can decode it. If you need to protect data, use proper encryption (AES, RSA) and then optionally Base64-encode the encrypted output for transport.

Don't embed large files. A 1MB image becomes 1.33MB when Base64-encoded and can't be cached separately by the browser. Use regular file hosting with CDN caching instead.

Don't store Base64 in databases when you can store raw binary. A BLOB column is more space-efficient than a TEXT column holding Base64 data. Only Base64-encode at the transport boundary.

Don't double-encode. A surprisingly common bug is Base64-encoding data that's already Base64-encoded. If your output looks like U0dWc2JHOHNJSGR2Y21sa0lR, you might have encoded twice.

Base64 and Performance

The 33% size overhead matters at scale. If you're Base64-encoding images in API responses serving millions of requests, that extra bandwidth adds up fast. Consider:

  • Serving binary data directly with appropriate Content-Type headers
  • Using multipart responses for mixed content
  • Returning URLs to binary resources instead of inline data

Wrapping Up

Base64 is a fundamental encoding that bridges the gap between binary data and text-based systems. It's simple, universal, and has clear use cases — but it's not encryption, and its 33% overhead means it should be used thoughtfully.

Understanding when and how to use Base64 will save you debugging time and help you make better architectural decisions. And when you need to quickly encode or decode something, our Base64 tool is always one click away.

Try the tool mentioned in this article:

Open Tool →