---
title: "Merge or patch YAML"
url: https://recursiveai.org/oneyaml/csharp/cookbook/patch-yaml/
description: "Apply a Merge Patch (RFC 7396) as an environment overlay and a guarded JSON Patch (RFC 6902) built with YamlPatch to a YAML file in C#, keeping its comments."
version: "1.2.1"
---

# Merge or patch YAML

Overlay one document on another, or apply a JSON Patch, without losing the file’s comments and layout. A Merge Patch suits environment overrides; a JSON Patch suits scripted changes with a `test` guard.

```csharp
using OneYaml;

using var doc = YamlDocument.Parse("""
    # values.yaml
    image:
      repository: registry.example.com/web
      tag: "1.4.2"   # set by CI
    replicas: 2
    resources:
      limits:
        cpu: 500m
        memory: 256Mi

    """);

// An environment overlay as a merge patch: objects merge, null deletes.
doc.ApplyMergePatch("""{ "replicas": 5, "resources": { "limits": { "cpu": null, "memory": "1Gi" } } }""");
Console.Write(doc);

// A JSON Patch with a guard, built in code: `test` must pass or nothing changes.
var bump = new YamlPatch()
    .Test("/image/tag", "1.4.2")
    .Replace("/image/tag", "1.5.0");
doc.ApplyPatch(bump);
Console.WriteLine($"tag now {doc.Get<string>("/image/tag")}");

// Applied again, the test fails and the document is left as it was.
try
{
    doc.ApplyPatch(bump);
}
catch (YamlException e) when (e.Category == YamlErrorCategory.PatchTest)
{
    Console.WriteLine($"second run refused at operation {e.OperationIndex}: {e.Message}");
}
```

```text
# values.yaml
image:
  repository: registry.example.com/web
  tag: "1.4.2"   # set by CI
replicas: 5
resources:
  limits:
    memory: 1Gi
tag now 1.5.0
second run refused at operation 0: The value at '/image/tag' is not the value the test expects.
```

## Good to know

- **Atomic.** If any operation fails, the document is unchanged. The `YamlException` has a `Category` (`PatchTest` for a failed test) and an `OperationIndex`.
- **A Merge Patch merges mappings and replaces everything else.** `null` deletes a key; a list in the patch replaces the whole list.
- **Only the named values change.** The `# set by CI` comment and the quotes around the tag stay.
- **YAML rules, not JSON rules.** `test` compares YAML values, so `1` and `1.0` differ. A value moved by `move` is written in the style of its new place, without its old comments.
- `ApplyPatch` takes JSON text, UTF-8 bytes, a `JsonNode` or a `YamlPatch`; `ApplyMergePatch` takes JSON text, UTF-8 bytes or a `JsonNode`. All six operations are supported.

Every rule is in [Patches](https://recursiveai.org/oneyaml/csharp/docs/patches/).

A longer guide: [Apply a JSON Patch to a YAML file](https://recursiveai.org/oneyaml/articles/json-patch-yaml/).
