Base64 Encoding and Decoding: A Complete Guide

If you've ever pasted an image into a CSS file, inspected a JWT token, or sent an email with an attachment, you've used Base64 — whether you knew it or not. It's one of the most common encoding schemes in computing, yet many developers treat it as a black box.

This guide explains what Base64 is, exactly how it works, when to use it, and what it absolutely should not be used for.

What Is Base64?

Base64 is a binary-to-text encoding scheme that represents arbitrary binary data using a set of 64 printable ASCII characters. The alphabet consists of:

Plus a special padding character = used to fill out the final group when the input length isn't a multiple of three bytes.

The core idea is simple: take every 3 bytes (24 bits) of input, split them into four 6-bit groups, and map each group to one of those 64 characters. Because 26 = 64, each character carries exactly 6 bits of information.

Why Base64 Exists

Many protocols and formats were designed to carry text only — specifically, 7-bit ASCII. When you need to move binary data (images, executables, compressed files) through these text-only channels, you have a problem: arbitrary byte values like 0x00 or 0xFF can corrupt the data or break the protocol.

Base64 solves this by encoding binary data into characters that every text-based system handles safely. Common scenarios include:

How the Encoding Works Step by Step

Let's encode the string Hi! into Base64 manually.

Step 1: Convert to ASCII Bytes

H  = 72  = 01001000
i  = 105 = 01101001
!  = 33  = 00100001

Step 2: Concatenate the Bits

01001000 01101001 00100001

That's 24 bits total (3 bytes).

Step 3: Split into 6-Bit Groups

010010 | 000110 | 100100 | 100001

Step 4: Map to Base64 Characters

6-Bit ValueDecimalBase64 Character
01001018S
0001106G
10010036k
10000133h

Result: Hi! encodes to SGkh.

What About Padding?

When the input isn't a multiple of 3 bytes, zero bits are appended to complete the final 6-bit group, and = characters are added to pad the output to a multiple of 4:

For example, encoding Hi (just 2 bytes):

H = 01001000, i = 01101001
Concatenated: 01001000 01101001
Pad to 18 bits: 01001000 01101001 00
6-bit groups: 010010 | 000110 | 100100
Base64 chars:  S        G        k
Add padding:   S        G        k       =
Result: SGk=

Tip: The padding = characters don't carry data — they simply signal how many trailing zero bits were added so the decoder knows the exact original byte count.

Base64 vs Base64URL

Standard Base64 uses + and / in its alphabet. That's fine for email and most contexts, but those characters have special meaning in URLs and filenames:

The Base64URL variant (defined in RFC 4648) fixes this with two substitutions and typically omits padding:

CharacterStandard Base64Base64URL
Index 62+-
Index 63/_
Padding= (required)Omitted (optional)

When to Use Which

Tip: JWTs always use Base64URL without padding. If you try to decode a JWT payload with a standard Base64 decoder, you'll get errors or garbage unless you first replace - with + and _ with /, then re-add padding.

Common Use Cases

Base64 appears in more places than most developers realise:

Embedding Images in CSS/HTML

/* Inline a small icon to avoid an extra HTTP request */
.icon {
  background-image: url(data:image/png;base64,iVBORw0KGgo...);
}

This is ideal for small images (under a few KB). For larger assets, a regular file is more efficient because the browser can cache it separately.

API Authentication Headers

# HTTP Basic Auth: username:password in Base64
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

JWT Payloads

A JWT token like eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.xxx contains three Base64URL-encoded segments: the header, the payload, and the signature.

Email Attachments

When you attach a PDF to an email, your mail client Base64-encodes the file and embeds it in the MIME message body with a Content-Transfer-Encoding: base64 header.

Storing Binary in JSON

{
  "name": "document.pdf",
  "content": "JVBERi0xLjQKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZw..."
}

APIs that accept file uploads via JSON payloads commonly expect a Base64-encoded string for the binary content.

Base64 Is NOT Encryption

Warning: Base64 is an encoding, not encryption. It provides zero security. Anyone can decode a Base64 string instantly — no key, no password, no secret required.

This is one of the most common misconceptions in web development. Developers sometimes Base64-encode sensitive data — API keys, passwords, tokens — thinking it obscures the value. It doesn't. Base64 is trivially reversible. It's a lookup table, not a cipher.

Consider HTTP Basic Auth: the credentials admin:secret123 become YWRtaW46c2VjcmV0MTIz. Anyone who sees that header can decode it in milliseconds. That's why Basic Auth must always be used over HTTPS — the transport encryption (TLS) provides the actual security, not the Base64 encoding.

Rules to live by:

Command-Line Examples

Both macOS and Linux have built-in tools for Base64 encoding and decoding.

Using base64

# Encode a string (macOS and Linux)
echo -n "Hello, World!" | base64
# Output: SGVsbG8sIFdvcmxkIQ==

# Decode a Base64 string
echo -n "SGVsbG8sIFdvcmxkIQ==" | base64 --decode
# Output: Hello, World!

# Encode a file
base64 -i photo.png -o photo.b64

# Decode a file
base64 --decode -i photo.b64 -o photo.png

Tip: Always use echo -n (no trailing newline) when encoding. Without -n, the newline character becomes part of the encoded data, producing a different result than you'd expect.

Using openssl

# Encode
echo -n "Hello, World!" | openssl base64
# Output: SGVsbG8sIFdvcmxkIQ==

# Decode
echo -n "SGVsbG8sIFdvcmxkIQ==" | openssl base64 -d
# Output: Hello, World!

Quick Base64URL Conversion in the Shell

# Standard Base64 → Base64URL (remove padding, swap chars)
echo -n "Hello, World!" | base64 | tr '+/' '-_' | tr -d '='
# Output: SGVsbG8sIFdvcmxkIQ

# Base64URL → Standard Base64 (restore for decoding)
echo -n "SGVsbG8sIFdvcmxkIQ" | tr '-_' '+/' | awk '{
  pad = (4 - length % 4) % 4;
  for(i=0;i<pad;i++) printf "=";
  print
}' | base64 --decode

Size Overhead

Base64 encoding always increases the data size by approximately 33%. Here's why:

Every 3 input bytes (24 bits) become 4 Base64 characters (each representing 6 bits). So the ratio is 4/3 — a 33.3% increase. A 1 MB file becomes roughly 1.33 MB when Base64-encoded.

Original SizeBase64 SizeOverhead
1 KB1.33 KB+33%
100 KB133 KB+33%
1 MB1.33 MB+33%
10 MB13.3 MB+33%

This overhead matters when you're embedding large assets inline. A 50 KB image as a data URI adds roughly 17 KB of bloat compared to serving it as a separate cached file. For small icons and sprites (under 2–4 KB), the trade-off is usually worth it to save an HTTP round-trip. For anything larger, serve it as a separate file.

Warning: Base64-encoded data in JSON APIs can be deceptive. A 10 MB video uploaded as a Base64 string in a JSON body becomes a 13.3 MB payload — and the entire JSON must be held in memory to parse. For large files, always prefer multipart form uploads.

Encode and Decode Instantly

BoltKit's Base64Lab tool lets you encode and decode Base64 on the fly — with support for the URL-safe variant, auto-detection, and instant results. Free on iPhone and iPad.

Get BoltKit Free