The Go encoding/base64 Mental Model
Go's encoding/base64 is arguably the cleanest Base64 API in any mainstream language. Unlike Python (str vs bytes), Node (Buffer vs string), or Java (older util.Base64 vs newer java.util.Base64), Go gives you four pre-configured*Encoding singletons and two functions: EncodeToString for in-memory, NewEncoderfor streaming. That's the whole surface area.
The four encodings:
base64.StdEncoding— RFC 4648 §4 (uses+and/, includes padding). Use for HTTP Basic Auth, MIME, data URLs.base64.URLEncoding— RFC 4648 §5 (uses-and_, includes padding). Use for URL query strings and filenames.base64.RawStdEncoding— StdEncoding without=padding.base64.RawURLEncoding— URLEncoding without=padding. Use for JWT headers and payloads.
Encoding a String — The Standard Pattern
package main
import (
"encoding/base64"
"fmt"
)
func main() {
text := "Hello 世界 👋"
// Step 1: string → []byte (Go strings are UTF-8 by default)
utf8Bytes := []byte(text)
fmt.Println(utf8Bytes) // [72 101 108 108 111 32 228 184 150 231 149 140 32 240 159 145 139]
// Step 2: []byte → Base64 string
encoded := base64.StdEncoding.EncodeToString(utf8Bytes)
fmt.Println(encoded) // SGVsbG8g5LiW55WMIPCfkYs=
// One-liner:
result := base64.StdEncoding.EncodeToString([]byte(text))
fmt.Println(result)
}Encoding a File
package main
import (
"encoding/base64"
"fmt"
"io"
"os"
)
func encodeSmallFile(path string) (string, error) {
// Read entire file into memory
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(data), nil
}
func encodeStreamingFile(inPath, outPath string) error {
// Streaming — for large files, does not load everything into memory
in, err := os.Open(inPath)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(outPath)
if err != nil {
return err
}
defer out.Close()
encoder := base64.NewEncoder(base64.StdEncoding, out)
if _, err := io.Copy(encoder, in); err != nil {
return err
}
// CRITICAL: Close flushes any remaining bytes and writes final padding.
// Without this, the last few bytes can be truncated.
return encoder.Close()
}
func dataURLFromImage(path string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
return fmt.Sprintf("data:image/png;base64,%s",
base64.StdEncoding.EncodeToString(data)), nil
}URL-Safe Base64 and JWT-Style Encoding
package main
import (
"encoding/base64"
"fmt"
)
func main() {
payload := []byte(`{"user_id":42,"role":"admin"}`)
// Standard Base64 (uses + and /)
std := base64.StdEncoding.EncodeToString(payload)
fmt.Println(std) // eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0=
// URL-safe Base64 (uses - and _)
urlsafe := base64.URLEncoding.EncodeToString(payload)
fmt.Println(urlsafe) // eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0=
// JWT-style: URL-safe + no padding
jwt := base64.RawURLEncoding.EncodeToString(payload)
fmt.Println(jwt) // eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0
// Decoding back
decoded, err := base64.RawURLEncoding.DecodeString(jwt)
if err != nil {
panic(err)
}
fmt.Println(string(decoded)) // {"user_id":42,"role":"admin"}
}Encoding a Struct via JSON
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Email string `json:"email"`
Roles []string `json:"roles"`
Joined string `json:"joined"`
}
func encodeUser(u User) (string, error) {
jsonBytes, err := json.Marshal(u)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(jsonBytes), nil
}
func decodeUser(encoded string) (*User, error) {
jsonBytes, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, err
}
var u User
if err := json.Unmarshal(jsonBytes, &u); err != nil {
return nil, err
}
return &u, nil
}
func main() {
user := User{
ID: 42, Email: "[email protected]",
Roles: []string{"admin", "editor"}, Joined: "2026-01-15",
}
encoded, _ := encodeUser(user)
fmt.Println(encoded)
decoded, _ := decodeUser(encoded)
fmt.Printf("%+v\n", *decoded)
}Building an HTTP Basic Auth Header in Go
package main
import (
"encoding/base64"
"fmt"
"net/http"
)
func basicAuthHeader(user, pass string) string {
creds := fmt.Sprintf("%s:%s", user, pass)
token := base64.StdEncoding.EncodeToString([]byte(creds))
return "Basic " + token
}
func callProtectedAPI() (*http.Response, error) {
req, err := http.NewRequest("GET", "https://api.example.com/protected", nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", basicAuthHeader("admin", "secret123"))
return http.DefaultClient.Do(req)
}
// Note: Go's http.Request also has SetBasicAuth which does this for you:
// req.SetBasicAuth("admin", "secret123")
// Prefer that method unless you need to construct the header manually.Common Pitfalls in Go Base64 Code
- Forgetting encoder.Close() — When using
NewEncoderfor streaming, the last few bytes stay buffered inside the encoder until Close() is called. Omitting Close() silently truncates output. Alwaysdefer encoder.Close()or handle the error explicitly. - Using StdEncoding for JWT tokens — JWTs need RawURLEncoding (URL-safe characters, no padding). Using StdEncoding produces tokens with
+,/, and=that get percent-encoded in URLs and rejected by JWT verifiers. - Ignoring the error from DecodeString — Base64 decoding fails on invalid input (wrong alphabet, corrupted padding). Always check the error return. Ignoring it produces empty bytes and confusing downstream failures.
- Mixing encoding variants on encode/decode— If you encoded with RawURLEncoding, decode with RawURLEncoding. Mixing StdEncoding and URLEncoding on the same data produces "illegal base64 data at input byte" errors.
- Assuming EncodedLen returns exact length —
StdEncoding.EncodedLen(n)gives you the buffer size needed for encodingninput bytes. Use it when pre-allocating buffers withEncode(dst, src)instead of the string-returningEncodeToString.
Command Line Alternative
For quick one-offs without writing a Go program, use the standard base64CLI or a Go one-liner via go run:
# Standard base64 CLI (present on macOS and most Linux distros)
echo -n "Hello" | base64
# Output: SGVsbG8=
# URL-safe base64 (some distros support --url-safe or -u)
echo -n "Hello" | base64 --url-safe
# Go one-liner (requires Go installed)
go run -e 'package main; import ("encoding/base64"; "fmt"); func main() { fmt.Println(base64.StdEncoding.EncodeToString([]byte("Hello"))) }'Key Facts
- Package:
- encoding/base64 (Go standard library — no go get needed)
- Standard encoding:
- base64.StdEncoding.EncodeToString(data)
- URL-safe encoding:
- base64.URLEncoding.EncodeToString(data)
- JWT-style encoding:
- base64.RawURLEncoding.EncodeToString(data) (URL-safe + no padding)
- Input type:
- []byte (convert string with []byte(s))
- Output type:
- string (returned directly — no decode step needed)
- Streaming API:
- base64.NewEncoder(enc, writer) — must call Close() to flush
- Concurrent safe:
- *Encoding singletons yes; Encoder/Decoder streams no
Related Base64 Tools
- Base64 Encode Online — general-purpose browser encoder
- Base64 Encode in Python — Python 3 equivalent
- Base64 Encode in JavaScript — Node.js and browser
- Base64 Encode in PHP — PHP base64_encode
- URL-Safe Base64 — cross-language URL encoding
- Base64 Decode Online — reverse the encoding
- JWT Debugger — inspect JWT tokens