Base64 Encoding & Decoding in Python
Python's standard library includes a base64 module with everything you need. The key thing to know: the module works with bytes, not strings — you need to encode/decode strings explicitly.
Basic Usage
import base64
# Encode: pass bytes, get bytes back
encoded = base64.b64encode(b"Hello, world!")
print(encoded) # b'SGVsbG8sIHdvcmxkIQ=='
print(encoded.decode()) # 'SGVsbG8sIHdvcmxkIQ==' (as string)
# Decode: pass bytes or string, get bytes back
decoded = base64.b64decode("SGVsbG8sIHdvcmxkIQ==")
print(decoded) # b'Hello, world!'
print(decoded.decode()) # 'Hello, world!' (as string)
Key pattern: str → .encode() → b64encode() → .decode() → str. Always encode your string to bytes before Base64-encoding, and decode the bytes result back to a string afterward.
Encoding Strings (Unicode-safe)
import base64
def encode_base64(text: str) -> str:
"""Encode a Unicode string to Base64."""
return base64.b64encode(text.encode("utf-8")).decode("ascii")
def decode_base64(b64: str) -> str:
"""Decode a Base64 string back to Unicode text."""
return base64.b64decode(b64).decode("utf-8")
print(encode_base64("Hello 🌍")) # "SGVsbG8g8J+MjQ=="
print(decode_base64("SGVsbG8g8J+MjQ==")) # "Hello 🌍"
URL-Safe Base64
Python's base64 module has dedicated functions for URL-safe Base64 (replaces + with - and / with _):
import base64
# URL-safe encode (with padding)
encoded = base64.urlsafe_b64encode(b"Hello, world!")
print(encoded) # b'SGVsbG8sIHdvcmxkIQ=='
# URL-safe decode
decoded = base64.urlsafe_b64decode(encoded)
print(decoded) # b'Hello, world!'
# Without padding (common for JWTs, tokens)
def urlsafe_b64encode_nopad(data: bytes) -> str:
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")
def urlsafe_b64decode_nopad(s: str) -> bytes:
# Restore padding
s += "=" * (4 - len(s) % 4)
return base64.urlsafe_b64decode(s)
Encoding Files
import base64
# Encode a file to Base64 string
with open("image.png", "rb") as f:
encoded = base64.b64encode(f.read()).decode("ascii")
print(encoded[:80] + "...") # iVBORw0KGgoAAAANSUhEUgAA...
# Decode Base64 back to file
with open("output.png", "wb") as f:
f.write(base64.b64decode(encoded))
For large files, use base64.encodebytes() which inserts newlines every 76 characters (MIME-compliant):
import base64
with open("large_file.pdf", "rb") as f:
# MIME-style with line breaks (for email attachments)
mime_encoded = base64.encodebytes(f.read()).decode("ascii")
# Decode MIME-style (handles embedded newlines)
decoded = base64.decodebytes(mime_encoded.encode("ascii"))
Encoding to Data URI (for HTML/CSS)
import base64, mimetypes
def file_to_data_uri(filepath: str) -> str:
mime_type, _ = mimetypes.guess_type(filepath)
if not mime_type:
mime_type = "application/octet-stream"
with open(filepath, "rb") as f:
encoded = base64.b64encode(f.read()).decode("ascii")
return f"data:{mime_type};base64,{encoded}"
# Usage
uri = file_to_data_uri("logo.png")
print(uri[:60]) # data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
Common Pitfalls
Passing a str instead of bytes to b64encode
base64.b64encode("Hello") # ❌ TypeError: a bytes-like object is required
base64.b64encode(b"Hello") # ✓ correct
Forgetting to strip whitespace before decoding
If your Base64 string came from a file or network response it may have newlines. b64decode() accepts a validate=False default that silently ignores invalid characters, or you can strip manually:
import base64, re
def safe_b64decode(s: str) -> bytes:
# Remove whitespace
s = re.sub(r"\s+", "", s)
# Restore padding if stripped
s += "=" * (4 - len(s) % 4)
return base64.b64decode(s)
Validating Base64 input
import base64
def is_valid_base64(s: str) -> bool:
try:
base64.b64decode(s, validate=True)
return True
except Exception:
return False
Test your Python Base64 output
Paste the encoded string from your Python script into base64.dev to verify it decodes correctly.
Open base64.dev →