Working with YAML in Go (Golang): Complete Guide
YAML (YAML Ain't Markup Language) is a human-readable data serialization format widely used for configuration files, infrastructure descriptions (e.g., Kubernetes, Docker Compose), and data exchange. In the Go (Golang) ecosystem, working with YAML is implemented through powerful third-party libraries, primarily go-yaml (known as gopkg.in/yaml.v3). In this article, we will thoroughly examine how to parse, create, and process YAML documents in Go.
Why is YAML important for a Go developer?
Go is a language for building high-performance server applications, DevOps tools, and microservices. YAML has become the de facto standard for:
- Application configurations (e.g.,
config.yaml); - Kubernetes manifests (
deployment.yaml); - CI/CD pipelines (GitLab CI, GitHub Actions);
- API and data schema descriptions.
Without the ability to work with YAML in Go, modern development in this language is unimaginable.
Main libraries for working with YAML in Go
Today, there are two main versions of the library:
- gopkg.in/yaml.v2 — old stable version, still popular;
- gopkg.in/yaml.v3 — current version with support for tags, channels, and improved error handling (recommended for new projects).
Both libraries provide Marshal (struct → YAML) and Unmarshal (YAML → struct) functions.
Installing the library
To get started, add the package to your project:
go get gopkg.in/yaml.v3Import it in your code:
import "gopkg.in/yaml.v3"Example 1: Parsing YAML into a struct (Unmarshal)
Let's create a configuration file config.yaml:
server: host: "localhost" port: 8080database: driver: "postgres" dsn: "host=localhost user=app password=secret dbname=mydb"logging: level: "info" file: "/var/log/app.log"Now let's write Go code to read this file:
package main
import ( "fmt" "os" "gopkg.in/yaml.v3")
type Config struct { Server ServerConfig `yaml:"server"` Database DatabaseConfig `yaml:"database"` Logging LoggingConfig `yaml:"logging"`}
type ServerConfig struct { Host string `yaml:"host"` Port int `yaml:"port"`}
type DatabaseConfig struct { Driver string `yaml:"driver"` DSN string `yaml:"dsn"`}
type LoggingConfig struct { Level string `yaml:"level"` File string `yaml:"file"`}
func main() { data, err := os.ReadFile("config.yaml") if err != nil { panic(err) }
var cfg Config err = yaml.Unmarshal(data, &cfg) if err != nil { panic(err) }
fmt.Printf("Server: %s:%d", cfg.Server.Host, cfg.Server.Port) fmt.Printf("Database driver: %s", cfg.Database.Driver) fmt.Printf("Log level: %s", cfg.Logging.Level)}Output:
Server: localhost:8080Database driver: postgresLog level: infoExample 2: Serializing a struct to YAML (Marshal)
Now let's create a struct and convert it to YAML:
package main
import ( "fmt" "gopkg.in/yaml.v3")
type AppConfig struct { Name string `yaml:"name"` Version string `yaml:"version"` Debug bool `yaml:"debug"` Tags []string `yaml:"tags"`}
func main() { cfg := AppConfig{ Name: "MyApp", Version: "1.0.0", Debug: false, Tags: []string{"production", "stable"}, }
out, err := yaml.Marshal(&cfg) if err != nil { panic(err) }
fmt.P