go-yaml v4.0.0
go-yaml v4.0.0 is the first stable release of the v4 series, maintained by the
YAML organization.
It adds configurable loading and dumping, public plugin interfaces, structured
errors, and a CLI for inspecting YAML processing.
The classic APIs remain supported, so applications can adopt v4 incrementally.
Getting started
Install the release:
go get go.yaml.in/yaml/v4@v4.0.0Use this import path in your Go code:
import "go.yaml.in/yaml/v4"For an existing v3 application, start by updating imports, reviewing custom
unmarshalers, and running your tests.
You can continue using Unmarshal, Marshal, NewDecoder, and NewEncoder.
The v2 and v3 APIs remain frozen, with security fixes only; new features and
routine bug fixes are developed in v4.
Why add Load and Dump?
Applications need different YAML policies: strict configuration validation,
particular output layouts, or custom anchor handling.
The new Load and Dump functions and streaming Loader and Dumper accept
functional options and plugins for those choices.
They use YAML's load/dump terminology and are recommended for new code.
The classic entry points keep compatibility settings rather than changing
formatting and error presentation for every existing caller.
Moving to the new API is an explicit choice to use v4 defaults, with presets
available when you want older settings.
Classic APIs remain supported.
For example, load a configuration with strict field checking, then choose its
output indentation:
package main
import (
"fmt"
"log"
"go.yaml.in/yaml/v4"
)
func main() {
var config struct {
Name string `yaml:"name"`
Port int `yaml:"port"`
}
input := []byte("name: api\nport: 8080\n")
if err := yaml.Load(input, &config, yaml.WithKnownFields()); err != nil {
log.Fatal(err)
}
output, err := yaml.Dump(config, yaml.WithIndent(4))
if err != nil {
log.Fatal(err)
}
fmt.Print(string(output))
}Unknown struct fields are ignored by default; WithKnownFields() opts into
rejecting them.
Duplicate mapping keys are rejected by default.
Options apply in order, so later options override earlier settings.
Defaults and compatibility
| Setting | Classic Marshal / Unmarshal | Load / Dump defaults |
|---|---|---|
| Output indentation | 4 spaces | 2 spaces |
| Sequence indentation | Non-compact | Compact |
| Quote preference | Legacy mixed quoting | Single quotes where possible |
| Preferred output width | Unlimited for Marshal | 80 characters |
| Error presentation | v3 style | v4 style with stage and position |
Quoting still depends on scalar content and styles, and line width is a
preference rather than a guaranteed maximum.
NewDecoder uses v3 error formatting; NewEncoder retains v3 output settings
with v4 error formatting.
Choose WithV3Defaults() to select compatibility defaults through the new API.
When replacing Marshal, also disable wrapping to match its line-width setting:
output, err := yaml.Dump(config,
yaml.WithV3Defaults(),
yaml.WithLineWidth(-1),
)Presets select defaults; they do not reverse every v4 bug fix or reproduce every
legacy code path.
For example, package-level Load requires exactly one document, whereas
Unmarshal retains legacy handling of empty input and trailing content.
WithSingleDocument() deliberately skips validation of later documents.
Use WithAllDocuments() to load or dump slices as document streams, or use a
streaming loader or dumper to process documents individually.
Options, plugins, and nodes
Options control indentation, sequence layout, quoting, document markers,
Unicode escaping, field validation, and more.
OptsYAML accepts YAML configuration for supported settings, which can also be
shared with the CLI.
The public plugin APIs cover six areas:
- Loader-Limits: configure depth and alias expansion checks.
- Merge-Key: control merge directives and mapping conflicts, or replace the
merge algorithm. - Alias-Data: supply external anchors, retain anchors across documents, use
dotted paths, or reject alias references. - Error-format: select error presentation or implement a custom formatter.
- YAML-parser: select an alternative parser implementation.
- Tab-indent: opt into tab-aware input and output indentation.
The core module provides implementations for these APIs.
Additional parsers live in separate modules, keeping their dependencies optional.
Existing depth and alias protections remain enabled by default.
yaml.Node gives access to tags, styles, comments, anchors, and source positions.
Node.Load and Node.Dump accept options for node conversion.
Pass construction options explicitly inside custom unmarshaler hooks;
Node.Load starts with fresh defaults independently of its calling loader.
Stream nodes can expose encoding and YAML directives.
Node output retains supported styles and comments without promising identical
source formatting.
Migration details to check
NewLoader and NewDumper return errors; check them before using the stream.
Check dumper Dump and Close errors as well.
Custom UnmarshalYAML(*yaml.Node) error hooks must use the v4 node type.
Recognized v3 node hooks produce a migration error rather than silently losing
custom behavior.
The legacy UnmarshalYAML(func(any) error) error callback remains supported.
Conversion failures return structured *yaml.LoadErrors values.
Use errors.As to inspect structured errors or match legacy *yaml.TypeError
values, rather than relying on a direct type assertion or fixed message text.
Review the migration guide
for the complete compatibility guidance.
Inspect YAML with the CLI
Install the CLI from this release:
go install go.yaml.in/yaml/v4/cmd/go-yaml@v4.0.0Convert to JSON, inspect nodes, or examine scanner and parser output:
go-yaml -J config.yaml
go-yaml -N config.yaml
go-yaml -T config.yaml
go-yaml -E config.yamlThe CLI also supports reusable options files and pipelines between intermediate
stages, making small bug reports easier to reproduce.
Runtime plugin selection chooses implementations already linked into the binary.
Further reading and thanks
See the options guide,
plugin guide,
CLI guide,
and API reference.
Please report problems with minimal input, a reproducer, and your Go version in
the issue tracker.
Release-candidate users should update to v4.0.0 and rerun their tests, as some APIs
changed during prerelease development.
Thanks to everyone who tested, reported problems, and contributed to this release.