Skip to content

Base64 のエンコードとデコード snippet

Base64 はエンコーディングであって暗号化ではありません — 誰でも元に戻せます。ただバイナリをテキストチャネルで安全に運べるようにするだけです。繰り返し現れる罠は Unicode です: 文字列そのものではなく、文字列の UTF-8 のバイト列を base64 化します。JavaScript の btoa が Latin-1 範囲外で例外を投げるのはまさにこのためです。2つ目の判断はアルファベット選択です: 標準 (+/) か URL-safe (-_) か、パディングの有無 — URL に載るトークンには URL-safe が必要です。C と C++ は省略: stdlib に base64 はありません。

Base64 はエンコーディングであって暗号化ではありません — 誰でも元に戻せます。ただバイナリをテキストチャネルで安全に運べるようにするだけです。繰り返し現れる罠は Unicode です: 文字列そのものではなく、文字列の UTF-8 のバイト列を base64 化します。JavaScript の btoa が Latin-1 範囲外で例外を投げるのはまさにこのためです。2つ目の判断はアルファベット選択です: 標準 (+/) か URL-safe (-_) か、パディングの有無 — URL に載るトークンには URL-safe が必要です。C と C++ は省略: stdlib に base64 はありません。

Runnable recipe · 13 languagesbase64 ツールを開く →
Crypto & Encodingbase64encodingutf-8url-safe

Every language

13 languages, copy-ready. One at a time with syntax highlighting, or all inline.

SQLSQLrunnable
SELECT encode(convert_to('héllo wörld', 'UTF8'), 'base64') AS encoded,
       convert_from(
           decode(
               encode(convert_to('héllo wörld', 'UTF8'), 'base64'),
               'base64'),
           'UTF8') AS roundtrip;

Pure Postgres built-ins — encode/decode need no extension. convert_to/convert_from bridge text and bytea; run it in the playground.

Run in the SQL playground →
JSJavaScript
// UTF-8 safe: encode to bytes FIRST — btoa alone throws on non-Latin1
const bytes = new TextEncoder().encode('héllo wörld');
const encoded = btoa(String.fromCharCode(...bytes));

const back = new TextDecoder().decode(
  Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0)),
);
console.log(encoded, '→', back);

In Node, Buffer.from(s, 'utf8').toString('base64') does both steps at once.

TSTypeScript
const encode = (s: string): string =>
  btoa(String.fromCharCode(...new TextEncoder().encode(s)));

const decode = (b64: string): string =>
  new TextDecoder().decode(
    Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)),
  );

console.log(encode('héllo wörld'));

String.fromCharCode(...bytes) spreads one arg per byte — it overflows the stack on inputs past ~100 KB. Buffer (Node) or a reduce loop for large payloads.

GoGo
encoded := base64.StdEncoding.EncodeToString([]byte("héllo wörld"))
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
	panic(err) // corrupt input, wrong alphabet, or bad padding
}
fmt.Println(encoded, string(decoded))

Pick the encoding by destination: StdEncoding, URLEncoding (- and _), RawStdEncoding (no padding). Mixing them up is the classic decode error.

RsRust
use base64::{engine::general_purpose::STANDARD, Engine as _};

let encoded = STANDARD.encode("héllo wörld");
let decoded = STANDARD.decode(&encoded)?;

println!("{encoded}");
assert_eq!(decoded, "héllo wörld".as_bytes());

base64 0.22+ hides everything behind the Engine trait — the old encode()/decode() free functions are gone. URL_SAFE is the URL-safe engine.

PHPPHP
$encoded = base64_encode('héllo wörld');
$decoded = base64_decode($encoded, strict: true);

if ($decoded === false) {
    throw new RuntimeException('invalid base64 input');
}
echo $encoded, PHP_EOL;

strict: true rejects whitespace and stray characters instead of silently stripping them. PHP strings are bytes — no UTF-8 pre-step needed.

PyPython
import base64

encoded = base64.b64encode('héllo wörld'.encode()).decode()
decoded = base64.b64decode(encoded).decode()
print(encoded)

b64encode takes bytes and RETURNS bytes — the outer .decode() turns it into str. urlsafe_b64encode swaps +/ for -_.

C#C#
// "..."u8 is a C# 11 UTF-8 literal — bytes with no intermediate string
var encoded = Convert.ToBase64String("héllo wörld"u8);
var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(encoded));

Console.WriteLine(encoded);

Convert handles standard base64 only — URL-safe needs WebEncoders.Base64UrlEncode (Microsoft.AspNetCore.WebUtilities) or a manual +/→-_ swap.

JvJava
import java.nio.charset.StandardCharsets;
import java.util.Base64;

String encoded = Base64.getEncoder()
        .encodeToString("héllo wörld".getBytes(StandardCharsets.UTF_8));

byte[] decoded = Base64.getDecoder().decode(encoded);
String original = new String(decoded, StandardCharsets.UTF_8);

getEncoder is standard; getUrlEncoder() is URL-safe; getMimeEncoder() wraps lines at 76 chars for email.

SwSwift
import Foundation

let data = Data("héllo wörld".utf8)
let encoded = data.base64EncodedString()

guard let decoded = Data(base64Encoded: encoded) else {
    fatalError("invalid base64") // the init is failable — bad input is nil
}
let original = String(decoding: decoded, as: UTF8.self)
print(encoded)

base64EncodedString(options: .base64UrlAlphabet) gives the URL-safe alphabet; the decoder auto-detects padding differences.

KtKotlin
import java.util.Base64

val encoded = Base64.getEncoder()
    .encodeToString("héllo wörld".toByteArray(Charsets.UTF_8))

val decoded = String(
    Base64.getDecoder().decode(encoded),
    Charsets.UTF_8,
)

Same java.util.Base64 as Java — toByteArray/String with explicit Charsets.UTF_8 is the Kotlin-idiomatic spelling.

RbRuby
require 'base64'

encoded = Base64.strict_encode64('héllo wörld')
decoded = Base64.strict_decode64(encoded)

puts encoded

strict_encode64 is the variant that matches other languages byte-for-byte; the fast primitive underneath is [s].pack('m0').

ZigZig
const std = @import("std");

pub fn main() !void {
    const input = "héllo wörld";

    // Zig computes buffer sizes up front — that arithmetic IS the exercise
    const enc_len = std.base64.standard.Encoder.calcSize(input.len);
    const enc_buf = try std.heap.page_allocator.alloc(u8, enc_len);
    defer std.heap.page_allocator.free(enc_buf);
    const encoded = std.base64.standard.Encoder.encode(enc_buf, input);

    const dec_len = try std.base64.standard.Decoder.calcSizeForSlice(encoded);
    const dec_buf = try std.heap.page_allocator.alloc(u8, dec_len);
    defer std.heap.page_allocator.free(dec_buf);
    try std.base64.standard.Decoder.decode(dec_buf, encoded);

    std.debug.print("{s} | equal: {}\n", .{ encoded, std.mem.eql(u8, input, dec_buf) });
}

std.base64.url_safe is the drop-in URL-safe variant. No padding is stripped by default — calcSizeForSlice validates the input length.

Keep going

Try the interactive base64 tool →