About the Base64 Encoder
Base64 encode text here and the result appears as you type. Your text is read as UTF-8, so é, 你好 and 👋 give the same Base64 as Node.js Buffer or Python's base64 module, and a URL-safe (Base64URL) switch gives you the variant used in JWTs and links.
Base64 (RFC 4648) writes any bytes with 64 plain characters: A to Z, a to z, 0 to 9, + and /, plus = for padding. You need it wherever a system only takes text: the Authorization: Basic header, the data fields of a Kubernetes Secret, data: URLs in CSS and HTML, email attachments, or a JSON field that has to carry a certificate. The encoding happens in your browser, so a password you encode for a Basic auth header stays on your machine.
- Put your text in Text to encode, or press Load sample for a line with accents, Chinese characters and an emoji.
- The Encoded text box updates a moment after you stop typing. There's no button to press.
- Turn on URL-safe (Base64URL) when the output goes into a URL parameter, a file name or a JWT. The note under the switch shows what changes:
-and_replace+and/, and the=padding is dropped. - Check the two numbers under the result. Input counts UTF-8 bytes, not characters, so it's higher than your text length when the text has multi-byte characters. Output is about four thirds of the input.
- Press Copy at the top right of Encoded text. If you pasted from a terminal or a file, check for a trailing line break first:
Helloencodes toSGVsbG8=, butHellofollowed by a newline givesSGVsbG8K.
InputAladdin:open sesameOutputQWxhZGRpbjpvcGVuIHNlc2FtZQ==This is the example from RFC 7617. The request header becomes Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==. Anyone who sees that header can decode it, so send it over HTTPS only.
InputZürich → 東京 👋OutputWsO8cmljaCDihpIg5p2x5LqsIPCfkYs=13 characters, but 23 bytes in UTF-8: ü takes 2 bytes, the arrow and each Chinese character take 3, and 👋 takes 4. Base64 works on bytes, so the output is 32 characters long.
Input<<???>>OutputStandard: PDw/Pz8+Pg==
URL-safe: PDw_Pz8-PgThe same bytes produce / and + in standard Base64. With URL-safe (Base64URL) on, they become _ and -, and the two = signs disappear.
How Base64 encoding works
The encoder reads the input 3 bytes at a time. Those 24 bits are cut into four groups of 6 bits, and each group, a number from 0 to 63, picks one character from the alphabet ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/. Here is Hi! done by hand:
- Bytes:
His 72,iis 105 and!is 33. In binary:01001000 01101001 00100001. - Regrouped into 6 bits:
010010 000110 100100 100001, which are the numbers 18, 6, 36 and 33. - Positions 18, 6, 36 and 33 in the alphabet are
S,G,kandh, soHi!encodes toSGkh.
Padding, size and what Base64 doesn't do
When the input isn't a multiple of 3 bytes, the end is padded. One leftover byte gives two characters and ==, two leftover bytes give three characters and =. So M is TQ==, Ma is TWE= and Man is TWFu. For n bytes the output is 4 * ceil(n / 3) characters, about a third more than the input.
Base64 hides nothing. There's no key, and the Base64 Decoder reverses it in one step. If a value has to stay secret, encrypt it first, for example with AES encryption, and use Base64 only to carry the ciphertext as text.
Base64 or Base64URL?
Standard Base64 uses + and /. In a URL, + is often read as a space, / splits the path, and = separates keys from values in a query string. RFC 4648 section 5 defines a URL and filename safe alphabet that uses - in place of + and _ in place of /, normally without padding.
- Standard Base64: MIME email,
data:URLs, HTTP Basic auth, Kubernetes Secrets, PEM certificates, and most APIs whose docs just say "Base64". - Base64URL: all three parts of a JWT (paste one into the JWT Decoder to see them), PKCE code challenges, WebAuthn data, URL parameters and file names.
- Check what the receiving side expects. Java's and Go's standard decoders reject
-and_, and Python'sb64decodequietly drops them, giving wrong bytes with no error, unless you passvalidate=True.
One line, or 76 characters per line?
The encoder here gives one unbroken line. That's what JSON, HTTP headers, environment variables and Kubernetes manifests expect. A few formats want line breaks:
- MIME email (RFC 2045) limits encoded lines to 76 characters. GNU
base64on Linux also wraps at 76 by default, which is how a value pasted from the terminal ends up breaking a YAML file. Runbase64 -w 0there to get one line. - PEM files, such as certificates and private keys, wrap at 64 characters between their BEGIN and END lines (RFC 7468).
- To wrap the output yourself, pipe it through
fold -w 76, or use a MIME encoder in code, such asBase64.getMimeEncoder()in Java.
Base64 encode a string in code
Each snippet encodes the UTF-8 bytes of the string. In JavaScript, btoa() only accepts characters with codes 0 to 255, so turn the text into UTF-8 bytes first.
const bytes = new TextEncoder().encode("Café 👋");
btoa(String.fromCharCode(...bytes));
// 'Q2Fmw6kg8J+Riw=='
// Above roughly 100 KB the spread can overflow the call stack,
// so build the string in chunks for big inputs.
// Current browsers also have toBase64() on byte arrays:
bytes.toBase64();
// 'Q2Fmw6kg8J+Riw=='
bytes.toBase64({ alphabet: "base64url", omitPadding: true });
// 'Q2Fmw6kg8J-Riw'Buffer.from("Café 👋", "utf8").toString("base64");
// 'Q2Fmw6kg8J+Riw=='
Buffer.from("Café 👋", "utf8").toString("base64url");
// 'Q2Fmw6kg8J-Riw'import base64
data = "Café 👋".encode("utf-8")
base64.b64encode(data).decode("ascii")
# 'Q2Fmw6kg8J+Riw=='
base64.urlsafe_b64encode(data).decode("ascii")
# 'Q2Fmw6kg8J-Riw==' (URL-safe, but keeps the = padding)base64.StdEncoding.EncodeToString([]byte("Café 👋"))
// URL-safe, no padding:
base64.RawURLEncoding.EncodeToString([]byte("Café 👋"))byte[] bytes = "Café 👋".getBytes(StandardCharsets.UTF_8);
Base64.getEncoder().encodeToString(bytes);
// URL-safe, no padding:
Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);Convert.ToBase64String(Encoding.UTF8.GetBytes("Café 👋"));// PHP strings are bytes; a UTF-8 source file gives UTF-8.
base64_encode("Café 👋"); // 'Q2Fmw6kg8J+Riw=='printf '%s' 'Hello, world!' | base64
# SGVsbG8sIHdvcmxkIQ==
# Don't use echo: it adds a newline, giving SGVsbG8sIHdvcmxkIQo=[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("Café 👋"))Base64 encode a file or an image
The encoder on this page takes text. For a file, encode its raw bytes in code, because reading a PNG or a PDF as text first corrupts every byte that isn't valid UTF-8. A data: URL is that Base64 with a data:<type>;base64, prefix. Inline only small images this way, a few kilobytes at most: the Base64 is a third bigger than the file, and the browser can't cache it separately from the page.
base64 -w 0 logo.png > logo.b64 # Linux (GNU coreutils)
base64 -i logo.png -o logo.b64 # macOS
# As a data: URL (Linux):
printf 'data:image/png;base64,%s' "$(base64 -w 0 logo.png)"import { readFileSync } from "node:fs";
const b64 = readFileSync("logo.png").toString("base64");
const dataUrl = "data:image/png;base64," + b64;import base64, pathlib
b64 = base64.b64encode(pathlib.Path("logo.png").read_bytes()).decode("ascii")
data_url = "data:image/png;base64," + b64const file = document.querySelector("input[type=file]").files[0];
const reader = new FileReader();
reader.onload = () => console.log(reader.result); // "data:image/png;base64,..."
reader.readAsDataURL(file);[Convert]::ToBase64String([IO.File]::ReadAllBytes("logo.png"))Is Base64 encoding the same as encryption?
No. Base64 only changes how bytes are written down. It has no key, so anyone with the string can turn it back into the original, and it gives no protection at all.
Why does Base64 end with = or ==?
The = signs are padding. Base64 works on groups of 3 bytes: == means the last group had one byte, = means it had two. Base64URL usually leaves them out, and most decoders accept the string either way.
How much bigger is Base64 than the original?
About 33%, because every 3 bytes become 4 characters. A 3 MB image becomes 4 MB of Base64, and a little more if the output is wrapped into lines.
Why is my Base64 different from the command line output?
The input bytes differ. echo 'Hello, world!' | base64 gives SGVsbG8sIHdvcmxkIQo= because echo adds a newline, while printf '%s' doesn't. A different text encoding (Latin-1 or UTF-16 instead of UTF-8) or Windows line endings change the result too.
Why does btoa() throw InvalidCharacterError?
btoa() accepts only characters with codes 0 to 255, so it fails on emoji and Chinese text. It's also wrong for accents without failing: btoa("Café") returns the Latin-1 Q2Fm6Q== instead of the UTF-8 Q2Fmw6k=. Encode the string with TextEncoder first.
How do I Base64 encode an image or a PDF?
Encode the file's bytes, not its text: base64 -w 0 file.pdf on Linux, base64 -i file.pdf on macOS, or read the file as bytes in your program. The In code tab has snippets for Node.js, Python, the browser and PowerShell, including how to build a data: URL.