Base64 is an encoding scheme that converts binary data into ASCII text. It is used when you need to transmit binary data — like images or files — over systems that only handle text, such as email, JSON APIs, or HTML data URIs.
When is Base64 used?
- Embedding images directly in HTML/CSS (
data:image/png;base64,...) - Encoding binary data in JSON API responses
- Email attachments (MIME encoding)
- Storing binary data in databases that only support text columns
- HTTP Basic Authentication headers (
Authorization: Basic dXNlcjpwYXNz) - Passing file contents as URL parameters
Base64 is NOT encryption
Base64 is purely an encoding format — anyone can decode it instantly. Never use Base64 to "protect" or "hide" sensitive data. If you need to secure data, use proper encryption (AES, RSA) — not encoding.
The string SGVsbG8gV29ybGQ= looks protected, but it simply decodes to Hello World.
How to encode text to Base64
- Go to Base64 Encoder
- Type or paste your text in the input field
- Select Encode mode
- Copy the Base64 output
How to encode a file to Base64
- Click the file upload zone or drag a file in
- Select any file (image, PDF, document, etc.)
- The Base64 string appears instantly — no upload to server
- Copy and use in your code or configuration
How to decode Base64
- Switch to Decode mode
- Paste the Base64 string
- The decoded text appears instantly
For binary files (images, PDFs), the tool will offer a download link for the decoded file.
Common Base64 examples
SGVsbG8gV29ybGQ=→Hello WorlddXNlcjpwYXNzd29yZA==→user:passwordeyJhbGciOiJIUzI1NiJ9→{"alg":"HS256"}(JWT header)
Standard vs URL-safe Base64
Standard Base64 uses + and / characters, which are not safe in URLs. URL-safe Base64 replaces these with - and _. Use the URL-safe option when embedding Base64 in query parameters.
Why Base64 exists at all
Base64 solves a specific problem: moving binary data through channels that only handle text safely.
Email was designed for 7-bit ASCII. Binary data contains bytes that older mail servers interpreted as control characters — a byte matching a line terminator could truncate a message mid-attachment. Base64 maps every 3 bytes of input onto 4 characters drawn from a 64-character alphabet that survives any text-safe channel intact.
The cost is size: output is roughly 33% larger than input, since 3 bytes become 4 characters. That overhead is the entire reason not to use it where a binary channel is available.
The 33% penalty in practice
Base64 in a data URI is the usual place this matters:
background: url('data:image/png;base64,iVBORw0KGgo...');
For a tiny icon this saves an HTTP request and is often worthwhile. For anything larger it backfires:
| Approach | Transfer | Cacheable | Blocks render |
|---|---|---|---|
<img src="photo.jpg"> |
100 KB | Yes, separately | No |
| Inlined base64 in CSS | 133 KB | Only with the whole stylesheet | Yes |
The second row is worse in three ways at once. The image cannot be cached independently, it inflates a render-blocking stylesheet, and it costs a third more bytes. Inline only small, rarely-changing assets — and prefer inline SVG for icons, which is smaller than base64 and stays sharp.
Reading the padding
The = characters at the end are padding, not data. Base64 works in 3-byte groups; when the input length is not divisible by 3, the final group is padded:
| Input bytes mod 3 | Padding |
|---|---|
| 0 | none |
| 1 | == |
| 2 | = |
So == means the original ended with one leftover byte. Some decoders require the padding and error without it, which is a common source of "invalid base64" when handling URL-safe variants that strip it.
URL-safe variant
Standard Base64 uses + and /, both of which have meaning in URLs — + decodes as a space in query strings and / is a path separator. The URL-safe alphabet substitutes - and _ and usually drops the padding.
This is why a JWT pasted into a generic Base64 decoder often fails or produces garbage: JWTs use Base64URL. Converting is a straight character swap:
const toStandard = (s) => s.replace(/-/g, '+').replace(/_/g, '/')
Unicode needs care
btoa() in JavaScript operates on Latin-1 and throws on any character above U+00FF:
btoa('héllo') // fine — é is U+00E9, inside Latin-1
btoa('日本語') // InvalidCharacterError
btoa('🎉') // InvalidCharacterError
The fix is to encode to UTF-8 bytes first:
const decode = (s) => new TextDecoder().decode(Uint8Array.from(atob(s), c => c.charCodeAt(0)))
// Note the loop rather than String.fromCharCode(...bytes): the spread pushes
// one argument per byte onto the call stack, so it throws
// "Maximum call stack size exceeded" somewhere above ~100 KB of input.
const encode = (s) => {
const bytes = new TextEncoder().encode(s)
let bin = ''
for (const b of bytes) bin += String.fromCharCode(b)
return btoa(bin)
}
Skipping this step is why encoded text with accents or emoji comes back mangled.
Frequently asked questions
Is Base64 a form of encryption?
No, and this is worth being emphatic about. It is a public, reversible encoding with no key. Anyone can decode it instantly. Credentials that are "base64 encoded" — including HTTP Basic Auth — are effectively plaintext to anyone who sees them.
Why does encoded data sometimes contain newlines?
MIME specifies a line length of 76 characters for email. Those newlines are formatting, not data, and most decoders ignore them. Some strict decoders do not, so strip whitespace if decoding fails.
Can I Base64 encode any file type?
Yes. It operates on raw bytes and is indifferent to what they represent — images, PDFs, executables all work.
How do I know a string is Base64?
Length divisible by 4, characters limited to A–Z a–z 0–9 + / =, and = only at the end. This is a heuristic, not proof — plenty of ordinary text satisfies it.
Is it safe to decode unknown Base64 here?
Decoding happens entirely in your browser and nothing is transmitted. Be careful what you do with the result, though: decoded content can be anything, including a malicious script.