Serialization in Go: Choosing the Right Format for the Right Job
What Is Serialization?
Serialization is the process of converting complex in-memory data structures — such as structs, maps, or slices — into a format that can be:
This serialized format could be JSON, XML, YAML, Protobuf, Avro, or others — depending on the use case.
Once data is received or retrieved, deserialization performs the reverse: it reconstructs the original data structure from the serialized format so that your application can work with it as native objects again.
Think of it like packaging and unpackaging your data — safely, efficiently, and consistently.
Why Does Serialization Matter So Much?
In real-world systems, serialization is the glue that connects services, stores state, and moves data across the wire.
Here’s how it powers modern applications:
👉 Choosing the wrong serialization format can lead to:
That’s why it’s crucial to understand when and why to use each format. In this article, we’ll dive deep into some of the most commonly used serialization formats in Go
JSON
JSON (JavaScript Object Notation) is a lightweight, text-based, language-independent data format. It is the most common serialization format used in REST APIs, web applications, and data interchange.
Below is an example of struct definition and serializing it in Golang using JSON:
type Order struct {
OrderID string `json:"order_id"`
Customer string `json:"customer"`
Items []string `json:"items"`
Total float64 `json:"total"`
Delivered bool `json:"delivered"`
}
order := Order{
OrderID: "ORD1001",
Customer: "Aslam",
Items: []string{"Phone", "Laptop"},
Total: 299.99,
Delivered: false,
}
jsonData, _ := json.MarshalIndent(order, "", " ")
fmt.Println(string(jsonData))
Use When:
Avoid When:
YAML
YAML (YAML Ain’t Markup Language) is a user-friendly, indentation-based format commonly used for configuration files like docker-compose.yaml, kubernetes.yaml, and CI/CD tools.
Below is an example of struct definition and serializing it in Golang using YAML:
type Config struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Debug bool `yaml:"debug"`
}
config := Config{"localhost", 8080, true}
yamlData, _ := yaml.Marshal(config)
fmt.Println(string(yamlData))
Use When:
Avoid When:
XML
XML (eXtensible Markup Language) is a structured, verbose format traditionally used in enterprise, banking, and government software.
Below is an example of struct definition and serializing it in Golang using XML:
type Invoice struct {
XMLName xml.Name `xml:"invoice"`
ID string `xml:"id"`
Amount float64 `xml:"amount"`
}
invoice := Invoice{"", "INV-123", 499.99}
xmlData, _ := xml.MarshalIndent(invoice, "", " ")
fmt.Println(string(xmlData))
Use When:
Avoid When:
Protobuf
Protocol Buffers (Protobuf) is a binary serialization format developed by Google. It’s schema-based, highly compact, and extremely fast.
Below is an example of struct definition using .proto file and serializing it in Golang using Protobuf:
// invoice.proto
syntax = "proto3";
message Invoice {
string id = 1;
float amount = 2;
}
//main.go
invoice := &pb.Invoice{Id: "INV-123", Amount: 499.99}
protoData, _ := proto.Marshal(invoice)
fmt.Printf("Serialized data: %x\n", protoData)
Use When:
Avoid When:
Conclusion
Serialization isn't just a technical detail — it's a core design decision that affects performance, maintainability, interoperability, and scalability of your system.
There’s no “one-size-fits-all” solution. Each format has its sweet spot:
The key takeaway? Choose the format that fits your use case—not just the one you’re most familiar with.