How-to Guide 5 min read

How to Base64 Encode and Decode in JavaScript, Python and the Terminal

Copy-ready Base64 encode and decode examples for JavaScript, Node.js, Python, Linux, macOS and PowerShell, including Unicode text and the newline mistake.

base64 encode javascriptbase64 encode pythonbase64 command line linuxbtoa unicode errorpowershell base64 encodebase64 decode terminal

The short answer

Every major language has Base64 built in: btoa() and atob() in browsers, Buffer in Node.js, the base64 module in Python, the base64 command on Linux and macOS, and [Convert]::ToBase64String in PowerShell. The one trap is text encoding: convert text to UTF-8 bytes first, or non-English characters will fail or decode wrongly. To check any result by hand, paste it into the free Base64 Encoder/Decoder, which encodes text as UTF-8 and decodes back to readable text.

All examples below use the text Hello, World!, which encodes to SGVsbG8sIFdvcmxkIQ==. The outputs shown were produced by running the code.

JavaScript in the browser

  • Encode: btoa('Hello, World!') returns SGVsbG8sIFdvcmxkIQ==
  • Decode: atob('SGVsbG8sIFdvcmxkIQ==') returns Hello, World!

btoa only accepts characters in the Latin-1 range. Hindi, emoji or Chinese text throws an InvalidCharacterError. Encode to UTF-8 bytes first:

  • Turn the text into bytes: const bytes = new TextEncoder().encode('नमस्ते')
  • Encode the bytes: const b64 = btoa(String.fromCharCode(...bytes)) gives 4KSo4KSu4KS44KWN4KSk4KWH
  • Decode back: new TextDecoder().decode(Uint8Array.from(atob(b64), c => c.charCodeAt(0))) gives नमस्ते
  • The spread into String.fromCharCode is fine for normal strings. For very large data, process it in chunks to avoid hitting the argument limit.

    Node.js

    Node has Buffer, which handles UTF-8 for you:

    • Encode: Buffer.from('Hello, World!', 'utf8').toString('base64') returns SGVsbG8sIFdvcmxkIQ==
    • Decode: Buffer.from('SGVsbG8sIFdvcmxkIQ==', 'base64').toString('utf8') returns Hello, World!

    To encode a file, read it as a buffer: fs.readFileSync('logo.png').toString('base64').

    Python

    Python's base64 functions work on bytes, so encode and decode the text explicitly:

    • First: import base64
    • Encode: base64.b64encode('Hello, World!'.encode('utf-8')).decode('ascii') returns SGVsbG8sIFdvcmxkIQ==
    • Decode: base64.b64decode('SGVsbG8sIFdvcmxkIQ==').decode('utf-8') returns Hello, World!

    For URL-safe Base64 (used in JWTs and some APIs), use urlsafe_b64encode. It swaps + for - and / for _. For the bytes FB FF, standard Base64 gives +/8= and URL-safe gives -_8=.

    Linux terminal

    • Encode: printf 'Hello, World!' | base64 prints SGVsbG8sIFdvcmxkIQ==
    • Decode: echo 'SGVsbG8sIFdvcmxkIQ==' | base64 -d prints Hello, World!

    To encode a file on one line, use base64 -w 0 file.png. Without -w 0, GNU base64 wraps long output every 76 characters, which breaks data URIs and JSON fields.

    The newline mistake

    echo 'Hello, World!' | base64 gives SGVsbG8sIFdvcmxkIQo=, not SGVsbG8sIFdvcmxkIQ==. The difference is because echo adds a line break at the end, and the line break is encoded too. Use printf or echo -n when you want to encode exactly the text you typed. This one detail explains a large share of "my Base64 doesn't match" questions.

    macOS terminal

    macOS also has a base64 command, but its options differ from the Linux version and have changed between macOS releases. printf 'Hello, World!' | base64 works the same way. For files and decoding, check man base64 on your Mac for the exact input, output and decode flags, rather than copying Linux flags such as -w.

    Windows PowerShell

    PowerShell uses .NET methods. Choose the text encoding explicitly:

    • Encode: [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('Hello, World!')) returns SGVsbG8sIFdvcmxkIQ==
    • Decode: [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('SGVsbG8sIFdvcmxkIQ==')) returns Hello, World!

    Some Windows tools and APIs expect UTF-16 text ([Text.Encoding]::Unicode) instead of UTF-8. The two give different Base64 for the same words, so use whichever the receiving system expects.

    Encoding files instead of text

    The same functions work on any bytes, not just text, which is how images, PDFs and certificates end up inside JSON, emails and HTML:

    • Node.js: fs.readFileSync('photo.jpg').toString('base64') returns the whole file as one Base64 string.
    • Python: open the file in binary mode and pass the bytes in: base64.b64encode(open('photo.jpg', 'rb').read()).decode('ascii').
    • Linux: base64 -w 0 photo.jpg prints it on a single line; redirect it with base64 -w 0 photo.jpg > photo.txt to save it.
    • PowerShell: [Convert]::ToBase64String([IO.File]::ReadAllBytes('photo.jpg')).

    Expect the output to be about a third larger than the file, because every 3 bytes become 4 characters. A 300 KB image becomes roughly 400 KB of text. That overhead is why Base64 suits small icons and attachments but not large photos.

    To use an encoded image in HTML or CSS, add the data URI prefix that names the file type, for example data:image/png;base64, followed by the encoded string. A wrong type in the prefix is one of the most common reasons an embedded image does not show. The image to Base64 converter adds the correct prefix for you.

    Quick reference

    EnvironmentEncodeDecode
    Browser JSbtoa(str) (Latin-1 only)atob(b64)
    Node.jsBuffer.from(s).toString('base64')Buffer.from(b64, 'base64').toString()
    Pythonbase64.b64encode(b)base64.b64decode(s)
    Linuxbase64base64 -d
    PowerShell[Convert]::ToBase64String(bytes)[Convert]::FromBase64String(s)

    Checking your output with the online tool

    When a script gives an unexpected result, compare it with a known-good encoder:

  • Open the Base64 Encoder/Decoder and choose Encode to Base64.
  • Paste the exact text. Watch for trailing spaces and line breaks; they are encoded too.
  • Compare the output with your script's. If only the last few characters differ, you almost certainly have an extra newline.
  • To decode, switch to Decode from Base64 and paste the string. If it is not valid Base64, the tool shows "Invalid Base64 string".
  • The tool converts text through UTF-8, so नमस्ते encodes to 4KSo4KSu4KS44KWN4KSk4KWH, the same as the Python and Node examples above. It works on text only; to turn an image into Base64, use the image to Base64 converter.

    Common errors and fixes

    • InvalidCharacterError from btoa: the text contains characters outside Latin-1. Use the TextEncoder method.
    • Padding errors when decoding: the string length must be a multiple of 4; missing = signs at the end cause errors in strict decoders. See fixing Base64 decode errors.
    • Garbled accented letters after decoding: the text was encoded as UTF-8 but decoded as Latin-1, or the reverse. Use the same encoding on both sides.
    • + and / breaking a URL: use URL-safe Base64, or URL-encode the result.

    Remember that Base64 is an encoding, not encryption. Anyone can decode it. For why it exists and how the 3-bytes-to-4-characters rule works, read Base64 encoding explained.

    Frequently asked questions

    How do I Base64 encode a string in JavaScript?

    In a browser use btoa(text) for plain English text. For Unicode text, convert to UTF-8 bytes with TextEncoder first. In Node.js use Buffer.from(text, "utf8").toString("base64").

    Why does echo | base64 give a different result?

    echo adds a line break to the end of the text, and base64 encodes that line break too. Use printf or echo -n to encode only the characters you typed.

    How do I decode Base64 in Python?

    Use base64.b64decode(s) to get bytes, then .decode("utf-8") to turn the bytes into text, for example base64.b64decode("SGVsbG8sIFdvcmxkIQ==").decode("utf-8") returns "Hello, World!".

    Why does btoa throw InvalidCharacterError?

    btoa only accepts characters in the Latin-1 range. Text with Hindi, emoji or other non-Latin characters must be converted to UTF-8 bytes before encoding.

    Try this tool on Lazyblink

    Put this guide into practice with our free online tool — no signup required.

    Open tool