---
title: "Read Kubernetes manifests and multi-document YAML"
url: https://recursiveai.org/oneyaml/csharp/cookbook/kubernetes-multi-document/
description: "Read every document of a multi-document YAML file such as a Kubernetes manifest into C# records with DeserializeAll, then edit one document and keep the rest byte for byte."
version: "1.2.1"
---

# Read Kubernetes manifests and multi-document YAML

A Kubernetes manifest often holds several documents separated by `---`. Read each one into a record with `DeserializeAll`, or edit one of them in a `YamlDocument` and write the whole file back with its comments.

The file:

```yaml
# Web frontend
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  template:
    spec:
      containers:
        - name: web
          image: registry.example.com/web:1.4.2 # pinned by release tooling
---
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  ports:
    - port: 80
      targetPort: 8080
```

The program:

```csharp
using OneYaml;

string src = File.ReadAllText("app.yaml");

// Typed: every document of the stream, in order.
using (var reader = new StringReader(src))
{
    foreach (var obj in YamlSerializer.DeserializeAll<K8sObject>(reader))
    {
        Console.WriteLine($"{obj!.Kind} {obj.Metadata.Name} ({obj.ApiVersion})");
    }
}

// Lossless: edit the Deployment, keep everything else byte for byte.
using var doc = YamlDocument.Parse(src);
int deploy = Enumerable.Range(0, doc.Documents.Count).First(i => doc.Get<string>("/kind", i) == "Deployment");
doc.Set("/spec/template/spec/containers/0/image", "registry.example.com/web:1.5.0", deploy);
Console.Write(doc);

record K8sObject(string ApiVersion, string Kind, Metadata Metadata);
record Metadata(string Name);
```

```text
Deployment web (apps/v1)
Service web (v1)
# Web frontend
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  template:
    spec:
      containers:
        - name: web
          image: registry.example.com/web:1.5.0 # pinned by release tooling
---
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  ports:
    - port: 80
      targetPort: 8080
```

## Good to know

- `YamlSerializer.DeserializeAll<T>` reads every document from a `TextReader` or a `Stream`; `DeserializeAllAsync` streams them as an `IAsyncEnumerable<T>`. `SerializeAll` writes a list back as a stream.
- A `YamlDocument` holds the whole stream. `Documents` lists the root of each, `Root` is the first, and every pointer method and patch takes a `document` index, 0 by default. Output always writes the whole stream.
- For manifests from outside, set `MaxDocuments` and the other limits ([read untrusted YAML safely](https://recursiveai.org/oneyaml/csharp/cookbook/untrusted-input/)).
