Base64 Encode Decode Cheatsheet: Windows, Linux, Mac Command Examples
Encode and decode Base64 on Windows, Linux, and Mac.
This cheatsheet shows how to encode and decode Base64 on Windows, Linux, and macOS with certutil, PowerShell, and base64, including the flags that differ by system.

This guide is part of Developer Tools: The Complete Guide to Modern Development Workflows. Base64 maps every three input bytes to four characters from A–Z, a–z, 0–9, +, and /. Decoding needs no key: the alphabet and the padding character = are enough to recover the original bytes.
Linux base64 wraps at 76 characters unless -w 0 is set, macOS base64 writes one line unless -b sets a break, and Windows certutil -encode adds certificate banners around wrapped lines. The Linux commands below were run with GNU coreutils 9.7, uutils coreutils 0.10.0, BusyBox 1.37.0, and OpenSSL 3.5.5. The macOS commands use the -i, -D, and -b flags documented for that binary since OS X 10.7.
Base64 Encode Decode on Windows
Windows does not ship a base64 command. Certutil and PowerShell are built in.
Using Command Prompt with Certutil
-
Open Command Prompt.
-
Encode a file to Base64:
certutil -encode input.bin output.b64Replace
input.binwith your file path andoutput.b64with the desired output filename. The file starts with-----BEGIN CERTIFICATE-----, then wrapped Base64, then-----END CERTIFICATE-----. -
Strip the banner lines and print the body:
certutil -encode input.bin tmp.b64 && findstr /v /c:- tmp.b64 && del tmp.b64findstr /v /c:-drops every line that contains-, which removes the two banners. The body stays wrapped. PowerShell[Convert]::ToBase64Stringis the one-line result.
Decode Base64 on Windows (Certutil)
certutil -decode encoded.b64 decoded.bin
certutil -decode accepts the banner file that -encode wrote. It also accepts a raw Base64 file.
Using PowerShell to Encode and Decode
PowerShell [Convert]::ToBase64String writes one line and does not add banners. For more shell automation, see the PowerShell Cheatsheet.
Encode a file:
[Convert]::ToBase64String([System.IO.File]::ReadAllBytes("C:\path\to\file.bin"))
Encode a string (UTF-8):
[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("Hello, World!"))
# Output: SGVsbG8sIFdvcmxkIQ==
Encoding.Unicode is UTF-16LE. The same characters then encode as SABlAGwAbABvACwAIABXAG8AcgBsAGQAIQA=. Linux base64 of the UTF-8 bytes produces SGVsbG8sIFdvcmxkIQ==.
Decode Base64 to string:
[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("SGVsbG8sIFdvcmxkIQ=="))
# Output: Hello, World!
Decode Base64 to file:
[System.IO.File]::WriteAllBytes("decoded.bin", [Convert]::FromBase64String((Get-Content encoded.b64 -Raw)))
FromBase64String accepts spaces, tabs, and newlines. It throws on the BEGIN CERTIFICATE banner, so a certutil file has to go through certutil -decode (or the banners have to be removed first).
Base64 Encode Decode on Linux
base64 --version names the binary on PATH. A line that starts with base64 (GNU coreutils) is GNU. On Ubuntu 25.10 and 26.04, /usr/bin/base64 is uutils from rust-coreutils; the 26.04 package checked here was uutils coreutils 0.10.0. GNU coreutils 9.7 is gnubase64 from the gnu-coreutils package.
Both accept a positional file, -d / --decode, -i / --ignore-garbage, and -w / --wrap. The default wrap is 76. -w 0 disables it. uutils 0.10.0 also treats -D as an alias of -d. GNU coreutils 9.7 exits with invalid option -- 'D' on -D.
Piping and quoting for these one-liners are covered in the Bash Cheat Sheet.
Encode a File to Base64
base64 input_file > output_file
Example:
base64 myfile.txt > encoded.txt
To print encoded content to the terminal:
base64 myfile.txt
Encode a String to Base64
printf '%s' 'Hello, World!' | base64 -w 0
# Output: SGVsbG8sIFdvcmxkIQ==
printf '%s' writes the bytes you pass and stops. echo without -n appends a newline, so the same text encodes as SGVsbG8sIFdvcmxkIQo=. In bash, echo -n "Hello, World!" | base64 -w 0 matches the printf line. echo -n is not portable to every sh.
Disable Line Wrapping (-w 0)
GNU and uutils wrap at 76 characters, including when stdout is a file or a pipe. JSON, environment variables, URLs, and a Kubernetes data value need one line. Terraform’s base64encode() returns one line of standard Base64, so CLI output that is compared with it has to be produced with wrap disabled:
base64 -w 0 input_file > output_file
Decode Base64 on Linux
base64 -d encoded_file > decoded_file
# or
base64 --decode encoded_file > decoded_file
Example:
printf '%s' 'SGVsbG8sIFdvcmxkIQ==' | base64 -d
# Output: Hello, World!
GNU coreutils since 9.5, and uutils 0.10.0, decode standard Base64 that omits = padding. printf '%s' 'SGVsbG8' | base64 -d prints Hello. Encoders still emit the padding. Older GNU base64 rejected unpadded input.
-i / --ignore-garbage skips characters outside the alphabet while decoding. Newlines are already allowed. Spaces are not, unless -i is set:
printf '%s' 'SGVs bG8=' | base64 -di
# Output: Hello
On GNU and uutils, -i does not take a filename. base64 -i input_file encodes input_file because the name is a positional argument and -i only changes decode. On macOS, -i is the input-file flag.
OpenSSL
OpenSSL 3.5.5 wraps at 64 characters. -A keeps the output on one line:
printf '%s' 'data' | openssl base64 -e -A
# Output: ZGF0YQ==
printf '%s' 'ZGF0YQ==' | openssl base64 -d -A
# Output: data
Without -A, a long buffer is broken every 64 characters, which is a different width from GNU base64.
BusyBox
BusyBox 1.37.0 accepts -d and -w COL (default 76, 0 disables wrap). --decode fails with unrecognized option '--decode', and -D fails with invalid option -- 'D'. Decoding already skips characters outside the alphabet: printf '%s' 'SGVs!bG8=' | busybox base64 -d prints Hello. -i is accepted and does not appear in the help line.
Base64 Encode Decode on macOS
macOS ships a BSD base64. A filename is passed with -i. Stdin redirection works without -i: base64 < input_file.
Encode a File to Base64
base64 -i input_file > output_file
Example:
base64 -i myfile.txt > encoded.txt
To print to the terminal:
base64 -i myfile.txt
The default break interval is 0, so the encoded text is one line. -b count inserts a newline every count characters. base64 -w 0 is the Linux option; the macOS binary does not use it. base64 -b 0 -i input_file is the explicit one-line form.
Encode and Copy to Clipboard
base64 -i input_file | pbcopy
Decode Base64 on Mac
base64 -D -i encoded_file > decoded_file
-D is decode. These -i and -D flags have been the macOS interface since OS X 10.7. A Linux script that calls base64 -d should call base64 -D on macOS.
Flags by Implementation
| Flag | GNU coreutils 9.7 | uutils 0.10.0 | BusyBox 1.37.0 | macOS |
|---|---|---|---|---|
-d / --decode |
Decode | Decode (-D is an alias) |
-d only; --decode errors |
Use -D |
-i |
--ignore-garbage while decoding |
--ignore-garbage while decoding |
Accepted, not listed in --help; non-alphabet bytes are already skipped |
Input file |
-w N |
Wrap at N columns (default 76); 0 disables |
Same default and 0 |
Same; no long option | Not this flag; use -b |
-b N |
Not accepted | Not accepted | Not accepted | Newline every N characters (default 0) |
| Help text alphabet | RFC 4648 | RFC 3548 | (no RFC line) | RFC 4648 |
RFC 4648 obsoletes RFC 3548. The standard alphabet in both documents is A–Z, a–z, 0–9, +, /.
base64 -i file encodes on Linux, because -i is a boolean there and file is the positional operand. The same command on macOS also encodes, because -i consumes file as the input path. base64 -D -i file decodes on macOS and on uutils 0.10.0.
Base64url for JWT
JWT header and payload segments use base64url (RFC 4648 section 5): - and _ replace + and /, and the = padding is usually omitted. Standard base64 -d then fails. On uutils 0.10.0 the error is invalid input.
GNU basenc (and gnubasenc on Ubuntu 26.04) accepts the unpadded form:
printf '%s' 'aGVsbG8_Ky93b3JsZA' | gnubasenc --base64url -d
# Output: hello?+/world
uutils 0.10.0 basenc --base64url -d requires padding restored to a multiple of 4. The same segment with == appended decodes. Encode and strip padding for a JWT-style token:
printf '%s' 'hello?+/world' | basenc --base64url -w 0 | tr -d '='
# Output: aGVsbG8_Ky93b3JsZA
jq decodes JWT segments with @base64d, which is the path in Decode and print JWT token.
PowerShell can build the same alphabet:
$b = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("hello?+/world"))
$b.TrimEnd("=").Replace("+","-").Replace("/","_")
Common Use Cases
| Use case | Command / approach |
|---|---|
| JWT header/payload | base64url, often unpadded. GNU basenc --base64url -d, or jq @base64d |
| HTTP Basic Auth | printf '%s' 'user:pass' | base64 -w 0 → Authorization: Basic dXNlcjpwYXNz |
| Kubernetes secret from a file | kubectl create secret generic mysecret --from-file=key=file.bin |
| Kubernetes secret from a string | kubectl create secret generic mysecret --from-literal=key=value |
| cURL Basic Auth | curl -u user:pass, or -H "Authorization: Basic $(printf '%s' 'user:pass' | base64 -w 0)" |
| Data URI in HTML | data:image/png;base64,$(base64 -w 0 image.png) on Linux |
kubectl create secret base64-encodes --from-literal and --from-file values itself. Prefixing the value with base64 -w 0, as in --from-literal=key=$(base64 -w 0 file.bin), stores a second encoding, and a later base64 -d still returns Base64. The Kubernetes cheatsheet uses the plaintext form, --from-literal=username=admin.
In a manifest, each data value is already one line of standard Base64, and stringData holds the raw string. The API server merges stringData into data. Kubernetes documents that stringData does not work well with server-side apply. The object is encoded text; etcd stores it unencrypted unless encryption at rest is turned on.
curl -u writes the Authorization: Basic header. Building that header from user:pass is covered in the cURL Cheatsheet.
When Decode Fails
base64 --version is the check when -D or -w misbehaves. The GNU line and the uutils line are different, and -D on Linux matches the uutils line.
A decoded value that ends with an empty line includes a newline from echo. Re-encode that input with printf '%s'.
base64 file | wc -l prints how many wrapped lines the encoder emitted. A count above 1 on Linux means the command was run without -w 0.
invalid input on text that contains - or _ is a base64url alphabet, typical of a JWT segment. Decode it with basenc --base64url, and on uutils 0.10.0 append = until the length is a multiple of 4.