Home Guides What Is Base64 Encoding and When Should You Use It?

What Is Base64 Encoding and When Should You Use It?

Understand how Base64 encoding works mechanically: the 6-bit grouping process, the 64-character alphabet, and the 33% size overhead. Covers data URIs, JWT tokens, Basic Auth, email MIME, and API payloads with JavaScript code examples. Learn why encoding is not encryption.

By Anurag · Published May 1, 2026 · Updated June 8, 2026 · ~11 min read

How Base64 Encoding Actually Works (The Mechanical Process)

Base64 takes binary data and converts it into a string built from exactly 64 printable ASCII characters: the 26 uppercase letters A-Z, the 26 lowercase letters a-z, the 10 digits 0-9, and the two symbols + and /. The = character appears only as padding at the end. Every piece of Base64 output you will ever see in production code is built entirely from these 65 characters.

The encoding process works in groups of three bytes at a time.

Take 3 bytes of input - that is 24 bits of raw data. Split those 24 bits into four groups of 6 bits each. Look up each 6-bit value, 0 through 63, in the Base64 alphabet. Output the corresponding character. Three bytes in, four characters out. That is the entire algorithm.

Walk through a real example with the string "Hi!":

  • "H" = ASCII 72 = 01001000
  • "i" = ASCII 105 = 01101001
  • "!" = ASCII 33 = 00100001

Combined into 24 bits: 010010000110100100100001

Split into four 6-bit groups: 010010 | 000110 | 100100 | 100001

Decimal values: 18, 6, 36, 33

Base64 alphabet lookup: S, G, k, h

Result: "Hi!" -> "SGkh"

"H" decimal 72 01001000
"i" decimal 105 01101001
"!" decimal 33 00100001
Split 24 bits into 4 groups of 6
01001018
0001106
10010036
10000133
Map to Base64 alphabet
S
G
k
h

You can verify this right now in any browser console: btoa("Hi!") returns "SGkh". The math is that mechanical.

btoa("Hi!");
// "SGkh"

btoa("Hi");
// "SGk="

When the input is not divisible by 3, padding fills the gap. One leftover byte produces 2 Base64 characters followed by ==. Two leftover bytes produce 3 Base64 characters followed by =. The string "Hi" is 2 bytes - two characters short of a clean group of three - so it encodes to "SGk=". The = is not meaningful data; it signals that the final group was padded to reach the required 4-character block size.

0A1B2C3D4E5F6G7H 8I9J10K11L12M13N14O15P 16Q17R18S19T20U21V22W23X 24Y25Z26a27b28c29d30e31f 32g33h34i35j36k37l38m39n 40o41p42q43r44s45t46u47v 48w49x50y51z520531542553 56457558659760861962+63/ pad=

The 33% Size Tax (and Why It Matters)

The math is unavoidable: 3 input bytes become 4 output bytes. That is a 33.3% size increase on every single Base64 encoding operation, no exceptions. The reason is straightforward - you are storing 6 bits of actual data inside an 8-bit ASCII character. 8 divided by 6 equals 1.333. The extra 2 bits per character is the overhead you pay to keep the output within printable ASCII.

Real numbers to keep in your head:

  • A 1KB file -> 1.37KB as Base64
  • A 100KB image -> 137KB as a Base64 data URI
  • A 1MB PDF attachment -> 1.37MB in MIME encoding
  • A 5MB image embedded as Base64 in HTML -> 6.85MB HTML file
1KB file1.37KB Base64 - 37% larger
1KB1.37KB
100KB image137KB Base64
100KB137KB
1MB PDF1.37MB Base64
1MB1.37MB
5MB image6.85MB Base64
5MB6.85MB

When Base64 travels via email using MIME encoding, line breaks are inserted every 76 characters, followed by a CRLF sequence. Those line break characters push the overhead from 33% to approximately 36-37%.

Where developers get burned by this: embedding images as Base64 in CSS files. A 20KB favicon encoded as a Base64 data URI adds 27KB to every CSS file download, for every visitor, on every page load, without any browser caching benefit applied to the image independently. Ten 50KB product images embedded as Base64 in a marketing email become 685KB of Base64 text instead of 500KB of linked images. The email is slower and heavier, and the images cannot be cached.

The size tax is the price of using a text channel to carry binary data. Pay it when you have to. Do not pay it when you do not have to.

Five Real Places You'll See Base64 in Production Code

1. Data URIs in HTML and CSS

A data URI embeds file content directly in markup or stylesheets using the format data:[mediatype];base64,[data].

<img src="data:image/png;base64,iVBORw0KGgo..." />
.icon {
  background-image: url(data:image/svg+xml;base64,PHN2Zy...);
}

Data URI code

<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZWY0NDQ0Ii8+PC9zdmc+" alt="Base64 red square">

Rendered result

Base64 red square

The legitimate use case is tiny assets - icons and SVGs under 2-3KB - where eliminating an HTTP request is worth the 33% size overhead. A 1KB inline SVG saves one network round trip. A 10KB inline PNG costs 13.7KB in your CSS file, cannot be cached independently, and bloats every page that imports that stylesheet. The crossover point where data URIs stop making sense is around 5KB. Above that, use a regular URL and let the browser cache the asset.

2. JWT Tokens

A JSON Web Token has three Base64url-encoded sections separated by dots: header.payload.signature. Base64url is a URL-safe variant that substitutes + with - and / with _ to prevent conflicts in URLs and HTTP headers.

// Decode a JWT header - no library needed
JSON.parse(atob('eyJhbGciOiJIUzI1NiJ9'));
// Returns: { alg: "HS256" }

The header and payload are encoded, not encrypted. Anyone who has the token can decode the payload without any key or credential. This is intentional - JWTs are designed for verification, not secrecy. The signature proves the token was issued by a trusted party; the payload is readable by anyone.

The failure mode that appears in production regularly: developers include sensitive data in JWT payloads - internal user IDs, role names, system details, API keys - under the mistaken assumption that Base64 encoding protects the data. It does not. If it needs to be secret, it does not belong in a JWT payload.

3. HTTP Basic Authentication

Basic Auth transmits credentials as base64(username:password) in the Authorization header.

const credentials = btoa('admin:secret123');
// Returns: "YWRtaW46c2VjcmV0MTIz"

// The header sent to the server:
// Authorization: Basic YWRtaW46c2VjcmV0MTIz

⚠️ Basic Auth depends on HTTPS

Decode that value in any browser console and you get "admin:secret123" back in one step. Basic Auth is not a security mechanism - it is an encoding mechanism that makes credentials safe to transmit in an HTTP header. Security comes entirely from HTTPS. Over plain HTTP, Basic Auth credentials are readable by anyone who can see the network traffic. Over HTTPS, the encoded string is protected by TLS. Never use Basic Auth without HTTPS.

4. Email Attachments (MIME)

The original email protocols were built for 7-bit ASCII text. Binary files - PDFs, images, executables - cannot be transmitted through those protocols directly. MIME, or Multipurpose Internet Mail Extensions, uses Base64 to convert binary attachments into text-safe strings, with line breaks inserted every 76 characters.

Content-Type: application/pdf; name="report.pdf"
Content-Transfer-Encoding: base64

JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwKL0xlbmd0aCAzIDAgUgo...

This is where the 33% overhead has direct user-facing consequences. A 10MB PDF attached to an email becomes approximately 13.7MB in the MIME-encoded message body. Corporate email size limits are measured against the encoded attachment size, not the original file size. When someone sends a batch of photos and hits a 25MB limit, the real file content is closer to 18MB - the rest is Base64 overhead.

5. API Payloads (JSON + Binary Data)

JSON is a text format. It has no native binary data type. When an API endpoint needs to deliver file content - an avatar image, a generated PDF, a signature - inside a JSON response body, Base64 is the standard way to encode it.

{
  "user_id": "u_8472",
  "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgAB..."
}

This works and is widely used. It is also the expensive option. For file uploads, multipart/form-data transmits binary directly without any encoding overhead - the 33% size tax disappears entirely. If you control both sides of the API and file sizes are non-trivial, multipart/form-data or a pre-signed URL upload approach will always be more efficient than Base64 in JSON.

Base64 in JavaScript: btoa(), atob(), and Buffer

The browser provides two global functions for Base64 operations. btoa stands for "binary to ASCII" - it encodes. atob stands for "ASCII to binary" - it decodes.

// Browser - basic encode/decode
const encoded = btoa('Hello, World!');
// "SGVsbG8sIFdvcmxkIQ=="

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

btoa has one significant limitation: it only accepts Latin-1 characters, code points 0-255. Passing a string containing emoji or non-Latin characters throws InvalidCharacterError. The standard workaround encodes Unicode to UTF-8 first:

// Browser - Unicode-safe encoding
const unicodeSafe = btoa(unescape(encodeURIComponent('Hello 🌍')));

// Decode it back
const original = decodeURIComponent(escape(atob(unicodeSafe)));

In Node.js, Buffer handles encoding without the Latin-1 restriction:

// Node.js - encode to Base64
const encoded = Buffer.from('Hello, World!', 'utf-8').toString('base64');
// "SGVsbG8sIFdvcmxkIQ=="

// Node.js - decode from Base64
const decoded = Buffer.from('SGVsbG8sIFdvcmxkIQ==', 'base64').toString('utf-8');
// "Hello, World!"

Complete round-trip for binary data in Node.js, which is the common pattern for processing file content through an API:

const fs = require('fs');

// Encode a file to Base64
const fileBuffer = fs.readFileSync('./image.png');
const base64String = fileBuffer.toString('base64');

// Decode Base64 back to a file
const decoded = Buffer.from(base64String, 'base64');
fs.writeFileSync('./image-restored.png', decoded);

The restored file is byte-for-byte identical to the original. Base64 is lossless - the encoding adds overhead but discards nothing.

Encoding Is Not Encryption (This Will Save Your Career)

🔒 Base64 is reversible by design

Base64 is reversible by anyone, instantly, with no key and no password. There is nothing to break. There is no algorithm to defeat.

atob('cGFzc3dvcmQxMjM=');
// "password123"

That took one function call. No credentials required. The person who encoded it did not protect anything.

Real encryption - AES-256, RSA, ChaCha20 - requires a key to decrypt. Without the key, the ciphertext is computationally infeasible to reverse. Base64 requires nothing. The alphabet is public. The algorithm is public. The transformation is deterministic and completely reversible by any developer in thirty seconds using tools built into every programming environment on the planet.

This distinction matters because the pattern of "store credentials as Base64 to obscure them" appears in production code regularly, often written by developers who genuinely believed they were adding a layer of security. They were not. They encoded their API key in Base64, pushed it to a public GitHub repository, and made it marginally more annoying to read than plain text - which is not the same thing as making it secure. It is the technical equivalent of writing your password in Pig Latin and leaving it on your desk.

If you encounter Base64-encoded credentials in a codebase - an API key, a database password, an OAuth secret - that is a security vulnerability, not a security practice. The credentials are exposed. Treat them as compromised and rotate them.

The legitimate uses of Base64 have nothing to do with secrecy: they are about format compatibility. Making binary data safe to travel through a text channel, embedding a file in a JSON field, fitting credentials into an HTTP header - these are transport problems that Base64 solves. Confidentiality is not one of them.

When to Use Base64 (Decision Checklist)

Use Base64 when:

  • You are transmitting binary data through a channel that only handles text - email, JSON payloads, XML, URL parameters. Base64 is the standard solution to this specific problem.
  • You are embedding tiny assets, under 2-3KB, as data URIs to eliminate an HTTP request. The size overhead is outweighed by the round-trip savings for very small files.
  • You need URL-safe encoding for binary data passed in query strings or path segments. Use the Base64url variant, - instead of +, _ instead of /, no padding, to avoid URL-encoding conflicts.

Do not use Base64 when:

  • The data is already text. Encoding a plain string as Base64 adds 33% size overhead and decoding complexity with no benefit. Send the string.
  • You are embedding images over 5KB as data URIs. The size penalty exceeds the request-elimination benefit, and the images cannot be independently cached.
  • You think encoding provides any form of security or obscurity worth having. It does not.
  • multipart/form-data is available for file uploads. The MIME boundary format transmits binary data at its actual size without any encoding overhead. Use it instead of Base64 in JSON whenever you control the API contract.

You can encode and decode Base64 strings instantly with Tooliest's browser-based Base64 Encoder and Base64 Decoder, or convert images to and from Base64 data URIs with the Image to Base64 and Base64 to Image tools - all free, no signup, processing stays in your browser.

About the Author

Anurag is the founder of Tooliest and reviews the site's browser tools, AI-assisted workflows, and editorial guides with a focus on privacy, practical clarity, and real-world usefulness.

Want the site-level context behind this guide? Visit About Tooliest, review the privacy policy, or read the site disclaimer before relying on output for sensitive work.

Frequently Asked Questions

Is Base64 a form of encryption?

No. Base64 is only an encoding method. Anyone with a decoder can turn it back into the original data immediately.

Why does Base64 make data larger?

Because it represents binary information using a text-safe character set, which expands the payload by roughly a third compared with the original bytes.

When is Base64 useful?

It is useful when binary data has to move through text-oriented systems, such as certain payload formats, email transport, or inline data URI workflows.

Should I Base64-encode large images for websites?

Usually not. It can make the payload heavier and harder to cache efficiently. It is more useful for small inline assets than for large media files.

Related Tooliest Tools