Base64 Encoding Explained: What It Is and When to Use It

A developer-friendly guide to Base64 encoding, decoding, and use cases.

Base64 encoding is one of those technologies that most developers use daily without fully understanding how it works. You've seen those massive strings in CSS files — data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA... — that seem to go on forever. In this guide, we'll demystify Base64 encoding, explain exactly how it works, and help you understand when it's the right tool for the job.

What Is Base64 Encoding?

Base64 is a binary-to-text encoding scheme that represents binary data as a string of ASCII characters. It's designed to safely transmit binary data through systems that only handle text — email (SMTP), URLs, XML, JSON, and more.

The "64" in Base64 refers to the 64 characters used in the encoding alphabet: 26 uppercase letters (A-Z), 26 lowercase letters (a-z), 10 digits (0-9), and two special characters (+ and /). A 65th character (=) is used for padding when the input length isn't a multiple of 3 bytes.

Why Does Base64 Exist?

Early internet protocols like email were designed to handle only ASCII text. When you tried to attach a binary file to an email, the protocol would corrupt the data. Base64 solves this by converting binary data to a text-only representation that survives transmission through text-based systems.

How Base64 Encoding Works

Base64 encoding operates on groups of 3 bytes (24 bits) at a time. Each group of 3 bytes is converted to 4 Base64 characters. Since each Base64 character represents 6 bits, and 4 characters × 6 bits = 24 bits, the round trip is lossless.

The Encoding Process

Here's a step-by-step example of encoding the text "Man" (3 bytes) to Base64:

  1. Convert each character to its ASCII value — M=77, a=97, n=110
  2. Convert each ASCII value to 8-bit binary — M=01001101, a=01100001, n=01101110
  3. Concatenate all bits — 01001101 01100001 01101110 (24 bits total)
  4. Split into 6-bit groups — 010011 010110 000101 101110 (4 groups)
  5. Convert each 6-bit group to a Base64 character — T, W, F, u
  6. Result — "Man" → "TWFu" in Base64

Handling Bytes That Aren't a Multiple of 3

What happens when your input isn't exactly 3 bytes? Base64 uses padding with the = character:

  • 1 byte of input → 2 Base64 characters + 2 padding (= =)
  • 2 bytes of input → 3 Base64 characters + 1 padding (=)
  • 3 bytes of input → 4 Base64 characters (no padding)

Base64 Encoding vs. Encryption

A common misconception: Base64 is not encryption. Base64 is encoding, not a security mechanism. The data encoded with Base64 can be instantly decoded by anyone who knows it's Base64 — the algorithm is public and trivially reversible.

Compare this with encryption, which uses a secret key and mathematical transformations to make data unreadable without the key. If you encode a password with Base64 and store it in a database, anyone who accesses that database can decode the password in milliseconds.

Never use Base64 for security purposes. For password storage, use bcrypt, scrypt, or Argon2. For data encryption, use AES-256 or ChaCha20-Poly1305. Base64 is for data transmission, not data protection.

When to Use Base64

1. Inline Images in HTML and CSS

Small images (icons, favicons, decorative elements) can be embedded directly in HTML or CSS using Base64 data URIs. This eliminates HTTP requests, which can improve performance for sites with many small assets.

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

However, there are trade-offs. Base64-encoded images are ~33% larger than the original binary file, they can't be cached separately from the HTML/CSS, and they can't be loaded in parallel. Use them only for very small images (under 4KB).

2. Embedding Binary Data in JSON

JSON doesn't have a binary data type. When your API needs to include binary data (file uploads, image thumbnails, document previews) in a JSON response, Base64 encoding is the standard solution.

{
  "filename": "photo.jpg",
  "data": "/9j/4AAQSkZJRgABAQEAYABgAAD..."
}

3. Email Attachments (MIME)

Email attachments use Base64 encoding via the MIME standard. When you attach a photo to an email, your email client encodes it with Base64, transmits it as text, and the recipient's client decodes it back to binary. This is why email attachments are ~37% larger than the original files.

4. URL Parameters

When you need to pass binary data through a URL, Base64 encoding ensures the data survives URL parsing. URLs can only contain ASCII characters, so Base64 provides a safe representation.

5. JWT Tokens

JSON Web Tokens use Base64url encoding (a URL-safe variant of Base64 that uses - and _ instead of + and /) to encode the header and payload sections. The three parts of a JWT are all Base64url-encoded strings separated by dots.

The Base64url Variant

Standard Base64 uses + and / as the 63rd and 64th characters. These characters have special meanings in URLs. Base64url, defined in RFC 4648, replaces these with - and _ to make the output URL-safe.

Base64url also omits padding characters (=). JWTs, URL parameters, and web tokens use Base64url, while email and file transmission use standard Base64.

Performance Considerations

Encoding Overhead

Base64 encoding increases data size by 33%: 3 bytes of binary become 4 characters. When deciding whether to use Base64, factor in the 33% overhead:

  • Inline images — For small icons under 4KB, the overhead is acceptable. For larger images, use external files that can be cached and compressed.
  • API responses — If your API returns large binary payloads, Base64 encoding makes responses 33% larger. Consider using multipart/form-data instead.
  • Storage — Storing Base64-encoded data in databases uses 33% more storage space. Store binary data as BLOBs when possible.

Decoding Performance

Modern JavaScript engines decode Base64 extremely quickly. The built-in atob() function decodes megabytes per second. For most web applications, Base64 decoding is not a performance bottleneck.

Base64 in Different Programming Languages

Every major programming language includes Base64 encoding/decoding in its standard library:

JavaScript

// Encode
const encoded = btoa("Hello, World!");  // "SGVsbG8sIFdvcmxkIQ=="

// Decode
const decoded = atob("SGVsbG8sIFdvcmxkIQ==");  // "Hello, World!"

Python

import base64

# Encode
encoded = base64.b64encode(b"Hello, World!")  # b'SGVsbG8sIFdvcmxkIQ=='

# Decode
decoded = base64.b64decode(b'SGVsbG8sIFdvcmxkIQ==')  # b'Hello, World!'

PHP

// Encode
$encoded = base64_encode("Hello, World!");  // "SGVsbG8sIFdvcmxkIQ=="

// Decode
$decoded = base64_decode("SGVsbG8sIFdvcmxkIQ==");  // "Hello, World!"

Common Base64 Mistakes

Mistake 1: Using Base64 for Large Images

Embedding a 500KB photo as a Base64 data URI in your HTML creates a 670KB string in the HTML file. This HTML file can't be cached separately, can't be compressed well, and blocks HTML parsing. Use external image files for anything larger than a few kilobytes.

Mistake 2: Forgetting Character Encoding

Base64 operates on bytes, not characters. If your input contains multi-byte UTF-8 characters, encode the string as UTF-8 bytes first. In JavaScript:

// Wrong — fails for non-ASCII characters
const encoded = btoa("Héllo");

// Correct — encode as UTF-8 first
const encoded = btoa(unescape(encodeURIComponent("Héllo")));

Mistake 3: Assuming Base64 Provides Compression

Base64 is encoding, not compression. It makes data larger, not smaller. If you need compression, use gzip or brotli after Base64 encoding.

Alternatives to Base64

Hex Encoding

Hex encoding represents each byte as two hexadecimal characters (0-9, A-F). It's easier for humans to read but produces strings twice as long as the original binary (vs. 1.33× for Base64).

Binary Transfer (multipart/form-data)

For file uploads, HTTP multipart/form-data is more efficient than Base64. The file is transmitted as raw binary with no encoding overhead. Use this for API file uploads instead of Base64-encoding the file into a JSON payload.

Base64 in Modern Web Development

Module Bundlers and Base64

Modern build tools like Webpack, Vite, and Rollup have built-in support for converting small assets to Base64 data URIs during the build process. This is controlled by the asset inline limit — typically set to 4KB or 8KB. Assets below this threshold are inlined as Base64 in the output bundle; larger assets are emitted as separate files with hashed filenames.

// Webpack 5 configuration
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8192 // 8KB threshold
          }
        }
      }
    ]
  }
};

This approach gives you the best of both worlds: tiny icons and UI elements are inlined (zero HTTP requests), while larger images remain as cacheable external files. The threshold is configurable — lower it if you're concerned about bundle size, raise it if you have many small assets and want to minimize requests.

Base64 in CSS Custom Properties

CSS custom properties (variables) can store Base64 data URIs, enabling dynamic theming where entire image assets swap based on user preference:

:root {
  --logo-light: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6bTAtMTZjLTQuNDEgMC04IDMuNTktOCA4czMuNTkgOCA4IDggOCAzLjU5IDgtOCAzLjU5LTggOC04LTIuNTktOC04IDMuNTktOCA4LTguNTkgOC04LTgtM3pNMTIgN2MxLjY2IDAgMyAxLjM0IDMgM3MtMS4zNCAzLTMgMy0zLTEuMzQtMy0zIDEuMzQtMyAzLTN6Ii8+PC9zdmc+");
  --logo-dark: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6bTAtMTZjLTQuNDEgMC04IDMuNTktOCA4czMuNTkgOCA4IDggOCAzLjU5IDgtOCAzLjU5LTggOC04LTIuNTktOC04IDMuNTktOCA4LTguNTkgOC04LTgtM3pNMTIgN2MxLjY2IDAgMyAxLjM0IDMgM3MtMS4zNCAzLTMgMy0zLTEuMzQtMy0zIDEuMzQtMyAzLTN6Ii8+PC9zdmc+");
}

@media (prefers-color-scheme: dark) {
  .logo { background-image: var(--logo-dark); }
}

This technique is especially powerful for icons and small decorative images that need to adapt to light/dark mode without additional HTTP requests.

Base64 and Content Security Policy

Content Security Policy (CSP) can restrict data URIs. If your site uses a strict CSP with img-src 'self' but no data: directive, Base64 images will be blocked. To allow Base64 images, add data: to your img-src directive:

Content-Security-Policy: img-src 'self' data: https:;

Alternatively, move Base64 images to external files to comply with stricter CSPs that prohibit data URIs entirely.

History of Base64

Base64 encoding predates the modern web. It was first standardized in 1987 with the publication of RFC 1341 (MIME: Mechanisms for Specifying and Describing the Format of Internet Message Bodies), which established the original Base64 alphabet for email attachments. The encoding was later refined in RFC 2045 and further standardized in RFC 4648 (2006), which introduced the URL-safe Base64url variant.

The need for Base64 arose from a practical constraint: early email systems and many internet protocols were designed to carry only 7-bit ASCII text. Binary data — images, PDFs, executables — would be corrupted by mail transfer agents that stripped high-bit characters or reinterpreted control sequences. Base64 provided a reliable workaround by mapping every 3-byte group to 4 printable ASCII characters, ensuring binary payloads survived any text-only transport.

Despite the rise of modern protocols that handle binary natively (HTTP/2, gRPC, WebSockets), Base64 remains ubiquitous because so many systems were built around it. Email continues to use it for attachments, JWT tokens rely on it for compact serialization, and countless APIs use it for embedding binary data in JSON. Understanding Base64 is understanding a fundamental building block of internet data transport.

Frequently Asked Questions

Is Base64 the same as encryption?

No. Base64 is encoding, not encryption. It's a reversible transformation that converts binary data to text. Anyone can decode Base64 data without a key. Never use Base64 for protecting sensitive data.

Why is Base64 33% larger than the original data?

Base64 uses 6 bits per character to represent 8 bits of binary data. This means 3 bytes (24 bits) become 4 characters (4 × 6 = 24 bits). The ratio is 4:3, which equals 33% overhead.

When should I use Base64 vs. external files?

Use Base64 for: small icons under 4KB, email attachments, JSON API responses containing binary data, JWT tokens. Use external files for: images larger than 4KB, anything that needs browser caching, content that benefits from CDN delivery.

Can Base64 data be compressed?

Yes, but not well. Base64 text uses a limited alphabet, so gzip typically reduces Base64-encoded data by only 20-30%. For best compression, compress the binary data first, then Base64-encode if necessary.

What is Base64url?

Base64url is a URL-safe variant of Base64 defined in RFC 4648. It replaces the + and / characters with - and _ to avoid conflicts with URL special characters, and omits padding characters.

External References & Further Reading


Avatar

Muhamad Satria | Sardev Studio

CEO / Co-Founder

Enjoy the little things in life. For one day, you may look back and realize they were the big things. Many of life's failures are people who did not realize how close they were to success when they gave up.