What is Base64? If you've ever seen a long string starting with data:image/png;base64,, you've seen it. It turns binary data into plain text so it can travel through systems built for text. It isn't encryption. This guide covers how it works, how much bigger it makes your data, where you'll meet it, and when I would and wouldn't use it.
What is Base64 encoding?
Base64 is a binary-to-text encoding defined in RFC 4648. It splits data into groups of 3 bytes (24 bits) and writes each group as 4 characters from a 64-character alphabet: A-Z, a-z, 0-9, + and /, with = as padding. Because 3 bytes become 4 characters, the output is about 33% larger than the input. It is used to put images in HTML or CSS, attach files to email, send credentials in HTTP headers and carry the parts of a JSON Web Token.
How Base64 works, step by step
Take the three letters Man. In ASCII they are bytes 77, 97 and 110:
M a n
01001101 01100001 01101110 (24 bits)
010011 010110 000101 101110 (four 6-bit groups)
19 22 5 46 (index into the alphabet)
T W F u
Base64: TWFu
Each 6-bit group is a number from 0 to 63, and the alphabet table in RFC 4648 maps 0 to A, 26 to a, 52 to 0, 62 to + and 63 to /. When the input isn't a multiple of 3 bytes, the last group is padded:
"Man" (3 bytes) -> TWFu
"Ma" (2 bytes) -> TWE=
"M" (1 byte) -> TQ==
Text with accents or emoji is converted to UTF-8 bytes first, so café (5 bytes, because é takes two) encodes to Y2Fmw6k=, and ✓ (3 bytes) encodes to 4pyT.
How much bigger Base64 makes your data
Padded Base64 output is 4 × ceil(n / 3) characters for n input bytes. For small inputs the padding makes the overhead larger than 33%:
| Input size | Base64 characters | Output ÷ input |
|---|---|---|
| 1 byte | 4 | 4.00 |
| 2 bytes | 4 | 2.00 |
| 3 bytes | 4 | 1.33 |
| 100 bytes | 136 | 1.36 |
| 1 KB (1,024 bytes) | 1,368 | 1.34 |
| 10 KB (10,240 bytes) | 13,656 | 1.33 |
| 1 MB (1,048,576 bytes) | 1,398,104 | 1.33 |
Email adds a little more. MIME limits Base64 lines to 76 characters (RFC 4648, section 3.1), so a 1 MB attachment also gets a line break after every 76 characters.
What is Base64 used for?
- Data URLs.
data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==is "Hello, World!" embedded straight in a link or page, using thedata:[<media-type>][;base64],<data>syntax described on MDN. For images, see how to Base64 encode an image in your browser. - Email attachments, which are usually sent with MIME's Base64 transfer encoding so binary files survive mail systems built for text.
- HTTP Basic authentication. RFC 7617 encodes
user:passwordin Base64, soAladdin:open sesameis sent asAuthorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==. - JSON Web Tokens. Each part of a JWT is base64url-encoded with the padding removed; how to decode a JWT safely walks through one, and the JWT decoder splits a token into its header and payload for you.
- Binary fields in JSON and XML. JSON has no type for raw bytes, so APIs that return a file, a key or a thumbnail inside a JSON response usually send it as a Base64 string.
Base64 and base64url
Standard Base64 uses + and /, which have meanings in URLs and file paths. RFC 4648 defines a variant called base64url that swaps them for - and _ and lets you drop the padding when the length is known. You can see the difference with the text <<???>>:
Base64: PDw/Pz8+Pg==
base64url: PDw_Pz8-Pg
How Base64 compares with hex, the other common way to write bytes as text, is covered in Base64 vs hex encoding.
The speed vs size trade-off
I often see developers Base64-encoding 1 MB images. Don't do this. Base64 makes files larger: that 1 MB image becomes 1,398,104 characters of text inside your HTML or CSS, and it can't be cached separately from the page. The only time I use it is for tiny icons (under 2 KB), where the overhead of a new HTTP request costs more than the extra 33% in size. For anything larger, I stick to external files.
Is it secure?
No. Base64 is easily reversible. RFC 4648 says it "does not provide any computational confidentiality", and anyone with a terminal can decode it in half a second:
$ echo 'cGFzc3dvcmQxMjM=' | base64 -d
password123
Never use it to "hide" passwords or sensitive data. It's for transmission, not protection. If something needs to be secret, encrypt it first.
How to recognise a Base64 string
A Base64 string uses only the 64 alphabet characters, has a length that is a multiple of 4 when it is padded, and can end in at most two = signs. Those rules tell you a string could be Base64, though plenty of ordinary words pass them too. The first characters are often more telling, because common file formats start with fixed bytes:
| Base64 starts with | Decoded data is | Because the bytes start with |
|---|---|---|
iVBORw0KGgo | PNG image | 89 50 4E 47 0D 0A 1A 0A |
/9j/ | JPEG image | FF D8 FF |
R0lGOD | GIF image | GIF87a or GIF89a |
JVBERi | PDF document | %PDF- |
eyJ | JSON object, such as a JWT header | {" and a letter |
So eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 is the JSON text {"alg":"HS256","typ":"JWT"}, a common JWT header.
How to Base64 encode and decode in code
Every mainstream language has Base64 built in. The usual problem is text: Base64 works on bytes, so text has to be turned into bytes first, and UTF-8 is the encoding you almost always want. In the browser, btoa() treats each character as one byte, so btoa("café") returns Y2Fm6Q== (the Latin-1 bytes, which other systems will decode wrongly) and btoa("✓") throws an InvalidCharacterError. Convert to UTF-8 bytes first:
// Browser: text to Base64 and back, UTF-8 safe
const bytes = new TextEncoder().encode("café");
const b64 = btoa(String.fromCharCode(...bytes)); // "Y2Fmw6k="
const text = new TextDecoder().decode(
Uint8Array.from(atob(b64), c => c.charCodeAt(0))
); // "café"
// Node.js
Buffer.from("café").toString("base64"); // "Y2Fmw6k="
Buffer.from("café").toString("base64url"); // "Y2Fmw6k"
# Python
import base64
base64.b64encode("café".encode("utf-8")) # b'Y2Fmw6k='
base64.b64decode("Y2Fmw6k=").decode("utf-8") # 'café'
base64.urlsafe_b64encode(b"<<???>>") # b'PDw_Pz8-Pg=='
Python's URL-safe function keeps the = padding, while Node's base64url and our tool's URL-safe option drop it. Both forms are allowed by RFC 4648, but a strict decoder on the other side may expect one or the other.
Common Base64 mistakes
- Encoding twice.
helloisaGVsbG8=, and encoding that again givesYUdWc2JHOD0=. If a decoded value still looks like Base64, it was probably encoded twice somewhere along the way. - Putting standard Base64 in a URL. In a query string,
+is read as a space, so?t=PDw/Pz8+Pg==arrives asPDw/Pz8 Pg==and no longer decodes to the same bytes. Use base64url, or percent-encode the value (PDw%2FPz8%2BPg%3D%3D) with a URL encoder. - Leaving line breaks in. The Linux
base64command wraps its output every 76 characters, and email bodies are wrapped the same way. Strict decoders reject the line breaks (Python'sb64decodedoes withvalidate=True), and a wrapped string pasted into our decoder usually fails with "Invalid Base64" as well, so usebase64 -w 0or strip the breaks first. - Expecting it to hide anything. As shown above, it decodes in one command.
Encode and decode with our Base64 tool
- Open the Base64 encoder and decoder. It works in your browser, so the text you paste isn't uploaded.
- On the Encode tab, type or paste text. It's encoded as UTF-8 as you type, and a line under the output shows the size change, for example 13 B to 20 B for "Hello, World!". Tick "URL-safe encoding" to get base64url without padding.
- On the Decode tab, paste a Base64 string. Both alphabets are accepted, and missing
=padding is added for you, soSGVsbG8decodes toHello. - The File Encode tab reads any file up to 5 MB. Its output box shows only the first 100 characters as a preview; the Copy as Data URI button copies the full
data:string. For pictures, the Image to Base64 converter gives you the complete Base64 string, the data URI, a CSS line and an<img>tag, each with its own copy button.
The decoder outputs text. If the bytes aren't valid UTF-8 text, such as an image, or the input contains characters outside the alphabet (such as @ or a data:...;base64, prefix), you get an "Invalid Base64" message instead of output. A space or line break inside the string can trigger it too, so paste one unbroken string.
Frequently asked questions
Why is it called Base64?
Because it uses 64 characters to represent data: A-Z, a-z, 0-9, and two symbols (+ and / in standard Base64, - and _ in base64url). Each character carries 6 bits, since 2 to the power of 6 is 64.
How do I decode Base64 on the command line?
On Linux, base64 -d decodes and plain base64 encodes: printf 'hello' | base64 prints aGVsbG8=. In Python, base64.b64decode() raises binascii.Error: Incorrect padding if the = signs are missing. By default it skips characters outside the alphabet; pass validate=True to have it reject them, which is what RFC 4648 recommends.
Can Base64 make data smaller?
No. It always adds about a third, plus padding. If size matters, compress the data first (for images, with an image compressor), then encode the result.