Golang base64 encode and decode with encoding/base64 and JSON

Tech reviewed: Deepak Prasad
Golang base64 encode and decode with encoding/base64 and JSON

Use encoding/base64 for golang base64 encode and golang base64 decode (and searches like base64 encode golang, base64 decode golang, or base64 golang). EncodeToString and DecodeString work on []byte and string. A separate sharp edge is JSON: json.Marshal encodes a []byte field as a base64 string in JSON, which drives queries such as golang json prevent encoding byte to base64 and go encoding/json marshal []byte base64 string. This page covers both. For JSON workflows, see JSON unmarshal in Go and parse JSON; for bytes and text, see bytes to string in Go. URL percent-encoding is different from Base64—see URL encode and decode.

Tested with Go 1.24 on Linux.


golang base64 encode and decode (standard)

go
package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	s := "Hello, world!"
	enc := base64.StdEncoding.EncodeToString([]byte(s))
	fmt.Println("encoded:", enc)

	raw, err := base64.StdEncoding.DecodeString(enc)
	if err != nil {
		panic(err)
	}
	fmt.Println("decoded:", string(raw))
}
Output

You should see a padded Base64 line then decoded: Hello, world!.


URL-safe base64 (URLEncoding)

Use base64.URLEncoding when the payload may sit in a query string or path without +// surprises:

go
package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	b := []byte{0xfb, 0xff, 0xbf}
	s := base64.URLEncoding.EncodeToString(b)
	out, err := base64.URLEncoding.DecodeString(s)
	if err != nil {
		panic(err)
	}
	fmt.Println(s, out)
}
Output

You should see the same three bytes round-trip.


Padding (NoPadding) and decoders

Some systems emit Base64 without = padding. Build an encoder with WithPadding(base64.NoPadding) and decode with the same alphabet and padding settings:

go
package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	enc := base64.StdEncoding.WithPadding(base64.NoPadding)
	s := enc.EncodeToString([]byte("Hi"))
	fmt.Println(s)

	dec := base64.StdEncoding.WithPadding(base64.NoPadding)
	b, err := dec.DecodeString(s)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(b))
}
Output

You should see SGk then Hi.


JSON: why []byte becomes Base64, and how to change it

By default, encoding/json marshals []byte as a Base64 JSON string (not a JSON array of integers). Example:

go
package main

import (
	"encoding/json"
	"fmt"
)

type Payload struct {
	Blob []byte `json:"blob"`
}

func main() {
	b, _ := json.Marshal(Payload{Blob: []byte{1, 2, 3}})
	fmt.Println(string(b))
}
Output

You should see "blob":"AQID" (Base64 of 0x010203).

Ways to avoid that default when you need something else:

  1. Use string for the field if the JSON should hold UTF-8 text (or your own hex/base64 layout you control).
  2. json.RawMessage when the value is already JSON bytes you want nested verbatim.
  3. MarshalJSON on a named type (type alias over []byte) to emit a custom JSON shape.

Illustration with string plus explicit Base64 you manage:

go
package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
)

type Payload struct {
	BlobB64 string `json:"blob_b64"`
}

func main() {
	raw := []byte{1, 2, 3}
	p := Payload{BlobB64: base64.StdEncoding.EncodeToString(raw)}
	out, _ := json.Marshal(p)
	fmt.Println(string(out))
}
Output

You should see a JSON object whose blob_b64 value is the same letters as EncodeToString, as a normal string field.


Encode small binary blobs (e.g. icons)

Read bytes with os.ReadFile (not deprecated ioutil), then EncodeToString for data: URLs or storage. This snippet skips a real file and encodes sample bytes so it stays self-contained:

go
package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	icon := []byte{0x89, 0x50, 0x4e, 0x47} // fake PNG header prefix
	s := base64.StdEncoding.EncodeToString(icon)
	fmt.Println("data:image/png;base64," + s)
}
Output

You should see a data:image/png;base64,... prefix suitable for HTML src attributes.


Summary

Golang base64 encode flows through base64.StdEncoding or URLEncoding, EncodeToString, and decode with DecodeString plus error checks (how to decode base64 data in golang). Match encoder and decoder for alphabet and padding. For APIs, remember json.Marshal treats []byte as Base64 in JSON; to match golang json prevent encoding byte to base64 expectations, switch the field type or implement custom JSON. Pair binary transport with bytes/string helpers when you cross text boundaries.


References


Frequently Asked Questions

1. How do I golang base64 encode a string?

Convert to bytes then base64.StdEncoding.EncodeToString([]byte(s)); for raw bytes use EncodeToString directly on the slice.

2. How to decode base64 data in golang?

Use base64.StdEncoding.DecodeString(s) which returns ([]byte, error); wrap with string() if you need text and validate errors from corrupt input.

3. Why does json.Marshal turn my []byte into a base64 string?

encoding/json marshals []byte as a base64-encoded JSON string by design; that matches how many APIs carry opaque binary in JSON.

4. How do I golang json prevent encoding byte to base64?

Store the payload in a string field, use json.RawMessage for already-JSON bytes, or define a named type with MarshalJSON that writes the shape you need instead of the default []byte rule.

5. What is the difference between StdEncoding and URLEncoding?

URLEncoding uses - and _ instead of + and / so the result is safer in URLs and filenames without extra escaping; pick one end-to-end for encode and decode.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, …

  • Red Hat Certified System Administrator in Red Hat OpenStack
  • Certified Kubernetes Application Developer (CKAD)
  • Red Hat Certified Specialist in Ansible Automation
  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security