Dev Encyclopedia
ArticlesToolsContactAbout

Get notified when new content drops

No spam. Just new articles, tools, and updates straight to your inbox.

Dev Encyclopedia

A reference for builders

Dev.to
Discord
WhatsApp Channel
daily.dev
Hashnode
X

Content

  • Articles
  • Tools
  • About
  • Contact

Connect

  • support@devencyclopedia.com
  • RSS Feed

Legal

  • Privacy Policy
  • Terms of Service
  • Disclaimer

© 2026 Dev Encyclopedia

Back to top ↑
  1. Home
  2. /
  3. Tools
  4. /
  5. Base64 Encoder / Decoder
Free · Private · No account

Encode or decode Base64 instantly.

Type or paste any text and get the Base64 output immediately, with no ads, no trackers, nothing sent to any server. Your input is processed entirely in your browser using JavaScript's built-in btoa() and atob() APIs.

Zeeshan Tofiq

Zeeshan Tofiq

Full Stack Developer

How this Base64 tool works

Six steps from the moment you paste to the moment you copy. All of them happen in the page: there is no request, no upload, and no server that ever sees your input.

  1. 1

    You pick a direction

    Encode turns plain text into Base64. Decode turns Base64 back into text. The labels above both boxes change with the mode, so you always know which side holds which.

  2. 2

    Your text is UTF-8 encoded first

    Before encoding, the input is converted to UTF-8 bytes. This is the step the browser's raw btoa() skips, and it is why btoa() throws on emoji, accented letters, and CJK text while this tool does not.

  3. 3

    Bytes are grouped three at a time

    Base64 reads 3 bytes (24 bits) and rewrites them as 4 characters of 6 bits each. When the input does not divide evenly by three, the last group is padded with one or two = characters so the output length stays a multiple of four.

  4. 4

    URL-safe mode rewrites two characters

    With the toggle on, + becomes - and / becomes _ after encoding, and the trailing = padding is stripped. That is the base64url variant used by JWTs and OAuth, and it survives being dropped straight into a query string.

  5. 5

    Decoding normalises before it decodes

    In Decode mode the input is trimmed, - and _ are mapped back to + and /, and any missing padding is restored. A JWT segment therefore decodes correctly without you touching the URL-safe toggle, which only affects encoding.

  6. 6

    Output is measured, copied, or swapped back

    Under each box you get a character count and a UTF-8 byte size, so the roughly 33 percent growth is visible. Copy puts the result on the clipboard, and Swap feeds the output back in as the new input with the mode flipped, which is the fastest way to verify a round trip.

What the output tells you

Base64 output is not opaque once you know what to look at. The alphabet, the padding, and the length all carry information about the input.

Standard output: Default encode mode

Only the 64 characters A-Z, a-z, 0-9, + and / appear, plus = as padding. Seeing + or / in a token tells you it is standard Base64, and that it must be percent-encoded before it goes into a URL.

Input   Hello, World!
Output  SGVsbG8sIFdvcmxkIQ==
One or two = characters at the end: Padding, not corruption

Padding tells you how many bytes the final group was short of three. No = means the input length divided evenly by three, one = means the last group held two bytes, two = means it held one. It is never part of the data.

"Man"  ->  TWFu     (3 bytes, no padding)
"Ma"   ->  TWE=     (2 bytes, one pad)
"M"    ->  TQ==     (1 byte, two pads)
Output with - or _ and no trailing =: URL-safe (base64url)

The URL-safe toggle produces this variant. It is what you see in JWT segments and OAuth state parameters. Decoders that only accept standard Base64 will reject it, which is the usual cause of a token that works in one library and fails in another.

Standard   a+b/c==
URL-safe   a-b_c

JWT header.payload.signature segments are all base64url
A red error panel instead of output: Input is not valid Base64

In Decode mode this appears when the string cannot be decoded. The usual causes are a character outside the alphabet (a stray quote, a space in the middle of a copied token), a truncated string, or accidentally pasting plain text while still in Decode mode.

SGVsbG8sIFdvcmxkIQ=   <- truncated padding
SGVsbG8s IFdvcmxkIQ== <- copied with a line break
Hello, World!         <- plain text, wrong mode
The character and byte counters: Size cost of encoding

Every 3 bytes in become 4 characters out, so encoded output is about 33 percent larger than the source. The exact output length is 4 times the input byte count rounded up to the next multiple of 3, divided by 3. For a 1 MB image that is roughly 1.37 MB of text.

Formula: outputChars = 4 * ceil(inputBytes / 3)

  12 bytes ->  16 chars
 100 bytes ->  136 chars
1024 bytes -> 1368 chars

Base64 format reference

The alphabet, the padding rules, and the wrappers you will meet in real payloads. Everything here is what the tool accepts on the input side.

The 64-character alphabet
Index  0-25   A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Index 26-51   a b c d e f g h i j k l m n o p q r s t u v w x y z
Index 52-61   0 1 2 3 4 5 6 7 8 9
Index 62-63   +  /        (standard)
Index 62-63   -  _        (URL-safe / base64url)
Padding       =           (standard only, stripped in URL-safe)
Worked example: how "Man" becomes "TWFu"
Text        M          a          n
ASCII       77         97         110
Bits        01001101   01100001   01101110

Regrouped   010011  010110  000101  101110
Index       19      22      5       46
Base64      T       W       F       u

3 bytes in, 4 characters out.
Input forms the decoder accepts
# Standard, fully padded
SGVsbG8sIFdvcmxkIQ==

# URL-safe, unpadded (padding is restored automatically)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

# Leading and trailing whitespace is trimmed
   SGVsbG8=

# Mixed alphabets: - and _ are mapped back to + and /
a-b_cQ==
Wrappers to strip before pasting
# Data URI: paste only what follows the comma
data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
                      ^ start here

# JWT: paste one segment at a time, without the dots
eyJhbGci....eyJzdWIi....SflKxwRJ
             ^ the payload is the middle segment

# PEM: drop the BEGIN and END lines, then join the body into one line
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBg...
-----END CERTIFICATE-----

# HTTP Basic: the header value is base64("user:password")
Authorization: Basic dXNlcjpwYXNzd29yZA==

One edge case worth knowing: MIME wraps long Base64 at 76 characters per line. Join those lines into a single string before decoding, because padding is recalculated from the length of what you paste.

When developers use Base64

Use caseExampleMode
HTTP Basic AuthAuthorization: Basic base64(user:pass)Encode
JWT payload inspectionDecode the middle segment of a JWTDecode
CSS data URIsdata:image/png;base64,iVBOR...Encode
Env var secretsEncode binary keys for .env filesEncode
API response dataSome APIs return files as Base64 stringsDecode
URL-safe tokensOAuth tokens, URL query parametersURL-safe

Standard Base64 vs URL-safe Base64

Standard Base64URL-safe Base64
CharactersA–Z, a–z, 0–9, +, /A–Z, a–z, 0–9, -, _
Padding= (included)Stripped
Safe in URLs?No (+ and / need escaping)Yes (no escaping needed)
Use forEmail, CSS data URIs, HTTP Basic AuthJWT tokens, OAuth tokens, URL params

Working with Base64 in JavaScript

Copy-paste patterns for the most common scenarios.

Browser: btoa() / atob()
// Encode
const encoded = btoa("Hello, World!");
// Decode
const decoded = atob(encoded); // "Hello, World!"
Browser: Unicode fix (emoji, accents, CJK)
// Encode Unicode safely
const encoded = btoa(unescape(encodeURIComponent("Hello 🌍")));
// Decode
const decoded = decodeURIComponent(escape(atob(encoded)));
Node.js: Buffer.from()
// Encode
const encoded = Buffer.from("Hello, World!").toString("base64");
// Decode
const decoded = Buffer.from(encoded, "base64").toString("utf-8");
URL-safe Base64 (JWT, OAuth tokens)
// Encode URL-safe
const encoded = btoa(unescape(encodeURIComponent(str)))
  .replace(/+/g, "-").replace(///g, "_").replace(/=/g, "");
// Decode URL-safe
const padded = str.replace(/-/g, "+").replace(/_/g, "/")
  + "=".repeat((4 - str.length % 4) % 4);
const decoded = decodeURIComponent(escape(atob(padded)));

Frequently Asked Questions

What is Base64 encoding?

Base64 converts binary data into a string of printable ASCII characters using a 64-character alphabet (A-Z, a-z, 0-9, +, /, =).

  • Why it exists: binary data breaks in text-only contexts (HTTP headers, email bodies, URL parameters, JSON values). Base64 makes any payload text-safe.
  • What it is not: Base64 is not encryption and not compression. Encoded output is ~33% larger than the original input.
  • Anyone can decode it: Base64 is fully reversible with no key. Never use it as a security mechanism.
Does Base64 encoding encrypt my data?

No. Base64 is encoding, not encryption. Anyone who sees a Base64 string can decode it immediately: there is no key involved.

⚠ Warning

JWT tokens look like gibberish but are simply Base64 URL-encoded. The header and payload are completely readable by anyone who decodes them. Only the cryptographic signature provides a security guarantee. Encrypt data before encoding it if confidentiality matters.

What is URL-safe Base64 and when should I use it?
Standard Base64URL-safe Base64
CharactersA–Z, a–z, 0–9, +, /A–Z, a–z, 0–9, -, _
Padding= (included)Stripped
Safe in URLs?No (+ and / need escaping)Yes
Use forEmail, CSS data URIs, HTTP Basic AuthJWT tokens, OAuth tokens, URL params

Toggle URL-safe mode in this tool when working with JWT payloads or encoding values that will appear in a URL.

How do I decode a JWT token's payload with this tool?

A JWT has three Base64 URL-encoded segments separated by dots: header.payload.signature.

  1. Copy the payload: the middle segment between the two . dots.
  2. Switch to Decode mode: the tool auto-detects URL-safe characters (- and _) and normalises them automatically.
  3. Paste the segment: the decoded JSON object appears immediately.

ℹ Info

The signature (third segment) cannot be verified here: that requires the secret key and a JWT library. This tool only decodes the readable claim data.

Why does btoa() throw an error on some strings in JavaScript?

The browser's native btoa() only accepts Latin-1 (ISO-8859-1) characters. Any input outside that range (emoji, accented letters, CJK characters) throws DOMException: The string to be encoded contains characters outside of the Latin1 range.

Fix: UTF-8 encode the string first:

javascript
// Encode Unicode safely
const encoded = btoa(unescape(encodeURIComponent(str)));

// Decode
const decoded = decodeURIComponent(escape(atob(encoded)));

💡 Tip

This tool handles Unicode automatically: paste any string including emoji and non-ASCII text without errors. The Node.js Buffer API also handles this natively: Buffer.from(str).toString('base64').

Why does my Base64 string end in = or ==, and can I remove it?

The = characters are padding. Base64 encodes three input bytes as four output characters, so when the input length is not a multiple of three the encoder pads the final group to keep the output a multiple of four.

One = means the last group held two bytes, two = means it held one byte. Padding carries no data, which is why the base64url variant used by JWTs drops it entirely.

InputInput bytesOutputPadding
Man3TWFunone
Ma2TWE=one =
M1TQ==two =

You can strip padding as long as the decoder restores it. This tool does that automatically: paste an unpadded string in Decode mode and it re-adds the = characters before decoding. Stricter decoders in other languages will throw instead, so keep the padding when you are not sure what will read the value.

Should I Base64 encode images or large files?

Rarely. Encoding inflates the payload by roughly 33 percent, and an inlined asset cannot be cached separately, so every page load ships it again.

  • Reasonable: tiny assets under a few KB where the saved request matters, such as an icon in a CSS background-image or an email signature logo.
  • Reasonable: APIs that must carry binary inside JSON, since JSON has no binary type.
  • Avoid: photos, fonts, and anything over about 10 KB. Serve them as files so the browser and your CDN can cache and compress them.
  • Avoid: storing large Base64 blobs in a database column when a file store plus a URL would do.

⚠ Warning

Base64 payloads also compress poorly compared with the original binary, so gzip or Brotli will not win the 33 percent back.

Related reading

Guide

Next.js Environment Variables

Encoding secrets before storing them in .env files: when to use Base64 and when to use proper secrets management.

Guide

How to Audit Your VS Code Extensions

Extensions can read Base64-encoded secrets from your workspace files. Know what's running in your editor.

Zeeshan Tofiq

Zeeshan Tofiq

Full Stack Developer

Full stack developer with over 6 years of experience building production applications. Writes practical guides on JavaScript, TypeScript, React, Node.js, and cloud infrastructure. Focused on helping developers solve real problems with clean, maintainable code.

Enjoyed this article?

Get practical dev guides, tool updates, and new articles delivered straight to your inbox. No spam, unsubscribe anytime.