encoding/xml, gob & Binary Formats
JSON covers most HTTP APIs, but Go also ships encoding/xml and encoding/gob for legacy feeds and Go-native binary caches.
Search across all documentation pages
JSON covers most HTTP APIs, but Go also ships encoding/xml and encoding/gob for legacy feeds and Go-native binary caches.
Protobuf and other binary codecs sit beside the stdlib when contracts cross languages or need compact wire sizes.
Pick the serializer to match the consumer: browsers and public REST stay on JSON; enterprise XML integrations use encoding/xml; Go-only process boundaries can use gob; gRPC services use protobuf.
Each format has different compatibility rules, security considerations, and debugging ergonomics.
Quick-reference recipe card - copy-paste ready.
// XML marshal
type Feed struct {
XMLName xml.Name `xml:"feed"`
Title string `xml:"title"`
Items []Item `xml:"item"`
}
b, err := xml.Marshal(Feed{Title: "News"})
// gob register + encode (Go-to-Go only)
gob.Register(User{})
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
_ = enc.Encode(User{ID: 1})When to reach for this:
package main
import (
"bytes"
"encoding/gob"
"encoding/xml"
"fmt"
)
type Item struct {
ID int `xml:"id" json:"id"`
Label string `xml:"label" json:"label"`
}
type Catalog struct {
XMLName xml.Name `xml:"catalog"`
Items []Item `xml:"item"`
}
type CacheEntry struct {
Key string
Items []Item
}
func main() {
cat := Catalog{Items: []Item{{ID: 1, Label: "bolt"}}}
xmlBytes, _ := xml.MarshalIndent(cat, "", " ")
fmt.Println(string(xmlBytes))
gob.Register(CacheEntry{})
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
_ = enc.Encode(CacheEntry{Key: "parts", Items: cat.Items})
dec := gob.NewDecoder(&buf)
var restored CacheEntry
_ = dec.Decode(&restored)
fmt.Println(restored.Items[0].Label)
}What this demonstrates:
xml.Name on XMLName sets the root element.gob.Register is required for interface values and non-exported concrete types in some cases.XML tags mirror JSON tags: xml:"field", xml:"-", xml:",attr" for attributes, xml:",chardata" for text nodes.
xml.Unmarshal is strict about matching start elements; namespaces may require xmlns attributes on structs.
Use XML when:
Avoid XML for new public mobile or browser APIs unless required.
gob encodes Go type information on the wire.
Both encoder and decoder must agree on registered types when interfaces are involved.
gob is not suitable for:
gob fits:
net/rpc style internal tooling (legacy; prefer gRPC for new work).| Format | Package / tool | Cross-language | Schema |
|---|---|---|---|
| Protobuf | google.golang.org/protobuf | Yes | .proto files |
| MessagePack | third-party | Yes | Informal |
| CBOR | third-party | Yes | Informal |
| gob | encoding/gob | Go only | Go types |
google.golang.org/grpc uses protobuf on HTTP/2; see gRPC Basics for codegen workflow.
// Prefer separate DTOs when XML and JSON shapes diverge
type UserXML struct { /* xml tags */ }
type UserJSON struct { /* json tags */ }Mixing many tag families on one mega-struct complicates reviews; split when wire shapes differ materially.
gob.Register for concrete types at init.XMLName or xmlns tags break unmarshal. Fix: mirror the partner sample XML exactly in tests.| Alternative | Use When | Don't Use When |
|---|---|---|
| JSON | Human debugging, HTTP APIs | Ultra-compact internal RPC |
| Protobuf/gRPC | Typed cross-service contracts | Quick scripts |
| gob | Same-repo Go cache | Any non-Go consumer |
| XML | Mandated partner format | Greenfield mobile clients |
| CSV | Tabular exports | Nested structures |
Yes when shapes align.
Split DTOs when attribute vs element layouts diverge.
Often yes for Go-to-Go paths because it avoids text parsing.
Measure on your payload sizes before committing.
Use xml.NewDecoder and xml.NewEncoder for large documents.
Same pattern as JSON decoders.
Prefer protobuf or JSON with schemas for anything persisted or inspected by operators.
gob is best for ephemeral process-local caches.
Protobuf has versioned field numbers and cross-language generators.
gob is simpler but Go-specific and type-coupled.
Verify at build for your board; XML reflection may be heavier than JSON.
Check stack footer targets.
Drivers handle BSON; you usually work with Go structs and tags at the application layer.
See database driver docs for tag conventions.
Not for new systems.
Use gRPC with protobuf for typed RPC.
You cannot read them in a text editor.
Log struct values before encode or use JSON in dev-only endpoints.
Yes - set Content-Type to application/json, application/xml, or gRPC's binary types.
Clients rely on headers for decode choice.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 18, 2026