Base64 is encoding, not encryption — and it makes data bigger
Base64 exists to carry binary data through channels that only accept text: email bodies,
JSON string fields, data: URIs, and HTTP headers. It maps every 3 bytes (24 bits)
of input onto 4 printable ASCII characters of 6 bits each. That is the whole trick, and it has
two consequences developers keep rediscovering.
It provides zero confidentiality. There is no key and nothing secret about the
transform — anyone can reverse it with one line (atob() in a browser,
base64 -d in a shell). A password or API key that has only been Base64-encoded is
effectively plaintext. If a value needs to stay private, it needs encryption, not encoding.
It inflates size by about 33%. Four output characters for every three input
bytes is a 4:3 ratio, so a 900 KB file becomes roughly 1.2 MB of Base64, before any
= padding or line breaks. This is exactly why a Base64-inlined image in your CSS or
an email attachment is larger than the original file, and why inlining large assets can cost
more than an extra request would have.
base64url, percent-encoding, and choosing the right escaper
Why JWTs use base64url instead of standard Base64
Standard Base64 uses +, /, and = in its output. All three
are hostile to URLs and filenames: / is a path separator, = delimits
query parameters, and + is decoded as a space in form data. The
base64url variant (RFC 4648 §5) swaps + for - and
/ for _, and usually drops the = padding. That is why a
JWT — which rides in URLs and Authorization headers — encodes all three of its
segments with base64url, not standard Base64.
Reserved vs unreserved characters in a URL
Percent-encoding replaces a character with % followed by the hex of its UTF-8
bytes. Under RFC 3986 the unreserved set — A–Z a–z 0–9 - . _ ~ — never
needs encoding. Reserved characters such as : / ? # [ ] @ ! $ & ' ( ) * + , ; =
carry structural meaning, so whether you encode one depends on whether you want it to act as a
delimiter or appear literally inside a value.
encodeURI vs encodeURIComponent
This is the JavaScript version of the same distinction, and mixing them up is a classic bug.
encodeURI() is meant for a whole URL, so it deliberately leaves reserved
characters like / ? : & = intact — they are doing their job. encodeURIComponent()
is for a single piece being dropped into a URL (a query-string value, a path segment), so it
also encodes those characters. Use encodeURI on a query value and an &
or = inside that value will not be escaped, silently breaking the query. When in
doubt for a single value, reach for encodeURIComponent.
HTML escaping is context-dependent
There is no single "HTML-safe" escaping. Replacing < and & makes
a value safe inside HTML text, but that same value is not automatically safe inside an
attribute (which also needs its quotes handled), and neither is safe inside a <script>
block, a style attribute, or a URL. Escape for the exact context the value lands in,
not "for HTML" in general.
Frequently Asked Questions
Is Base64 a form of encryption?
No. Base64 has no key and provides zero confidentiality — it is a public, reversible transform anyone can decode with atob() or base64 -d. It exists to move binary data through text-only channels, not to protect it. Anything that must stay secret needs real encryption.
Why is my Base64 output larger than the original file?
Because Base64 encodes every 3 bytes as 4 ASCII characters, output is about 33% larger than the input, plus any padding and line breaks. That overhead is inherent to the format, which is why inlining large images as Base64 data: URIs increases page weight.
What is the difference between Base64 and base64url?
They encode the same bytes but use a different alphabet for two characters. Standard Base64 uses + and /; base64url uses - and _ and usually omits = padding, so the result is safe in URLs, filenames, and HTTP headers. JWT segments use base64url for exactly this reason.
Should I use encodeURI or encodeURIComponent?
Use encodeURIComponent for a single value going into a URL, such as a query-string parameter — it escapes reserved characters like & = ? /. Use encodeURI only on a complete URL, where those characters must stay intact to act as delimiters. Encoding a query value with encodeURI is a common source of broken links.
Why does a "+" in my URL turn into a space?
In the application/x-www-form-urlencoded format used by query strings and form bodies, a space is encoded as +, so a decoder reads + back as a space. To include a literal plus sign in a value, percent-encode it as %2B.