---
title: "Parse YAML into Go structs"
url: https://recursiveai.org/oneyaml/go/cookbook/parse-yaml-into-structs/
description: "Read a YAML file into Go structs with oneyaml, with yaml tags, time.Duration, maps, an optional section, defaults and KnownFields to catch typos."
version: "1.0.0"
---

# Parse YAML into Go structs

Read a YAML file into typed Go data: nested structs, a map, an optional section, durations and defaults. `oneyaml.Unmarshal` works like `encoding/json`’s, with `yaml` struct tags.

The file:

```yaml
# service.yaml
name: web
image: nginx:1.27
timeout: 30s
env:
  LOG_LEVEL: info
  PORT: "8080"
healthcheck:
  path: /healthz
  interval: 10s
```

The program:

```go
package main

import (
	"fmt"
	"log"
	"os"
	"time"

	oneyaml "oneyaml.dev/go"
)

type Service struct {
	Name        string            `yaml:"name"`
	Image       string            `yaml:"image"`
	Replicas    int               `yaml:"replicas,omitempty"`
	Timeout     time.Duration     `yaml:"timeout"`
	Env         map[string]string `yaml:"env"`
	Healthcheck *Healthcheck      `yaml:"healthcheck"`
}

type Healthcheck struct {
	Path     string        `yaml:"path"`
	Interval time.Duration `yaml:"interval"`
}

func main() {
	src, err := os.ReadFile("service.yaml")
	if err != nil {
		log.Fatal(err)
	}
	svc := Service{Replicas: 1} // defaults: a missing key keeps the field as it is
	if err := oneyaml.Unmarshal(src, &svc, oneyaml.KnownFields()); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s runs %s x%d, timeout %v\n", svc.Name, svc.Image, svc.Replicas, svc.Timeout)
	fmt.Println("env:", svc.Env)
	if h := svc.Healthcheck; h != nil {
		fmt.Printf("health check: %s every %v\n", h.Path, h.Interval)
	}

	// KnownFields: a key the struct doesn't have is an error, not ignored.
	err = oneyaml.Unmarshal([]byte("name: web\nimgae: nginx\n"), &svc, oneyaml.KnownFields())
	fmt.Println(err)
}
```

```text
web runs nginx:1.27 x1, timeout 30s
env: map[LOG_LEVEL:info PORT:8080]
health check: /healthz every 10s
oneyaml: line 2, column 1: /imgae: field "imgae" not found in type main.Service
```

## Good to know

- **Defaults:** set them on the value before `Unmarshal`. A key that isn’t in the file leaves its field as it was, so `Replicas` stays 1. A `null` value also leaves a struct field, number or string as it was.
- **`KnownFields()`** makes a key the struct doesn’t have an error that names it, with its position. Without it, unknown keys are ignored.
- `time.Duration` reads its `String` form (`30s`, `1m30s`), `time.Time` a timestamp, and `*big.Int` any integer.
- `PORT: "8080"` is quoted, so it is a string. Plain `8080` is an integer; reading it into a `string` field is a `*TypeError`, not a silent conversion.
- Types with an `UnmarshalYAML` method, `encoding.TextUnmarshaler` or `json.Unmarshaler` read themselves, so types written for `encoding/json` (Kubernetes quantities, say) need no YAML code.

When the shape isn’t known ahead of time, read nodes from a `Document`: [read YAML without a struct](https://recursiveai.org/oneyaml/go/cookbook/read-yaml-without-a-struct/).
