README
¶
k8s-object-diff-go
objdiff - k8s object diff by object id
Usage
objdiff [flags] LEFT_FILE RIGHT_FILE
Either LEFT_FILE or RIGHT_FILE can be set to "-". Here, "-" represents stdin.
Object ID
A unique ID for a k8s object. e.g.
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
then id is 'v1>Pod>default>nginx'.
Output format
idlist
All object IDs.
id
ID diff.
text
Unified diff.
yaml
Array of
id: "Object ID"
diff: "Unified diff"
left: "Left object (optional)"
right: "Right object (optional)"
type: "Diff type (add or change or destroy)"
markdown
# Objdiff Summary: Left file <-> Right file
| **add** | **change** | **destroy** |
| :---: | :---: | :---: |
| x | y | z |
<details>
<summary><b>Diff type</b> <code>Object ID</code></summary>
Unified diff
</details>
or
# Objdiff Summary: Left file <-> Right file
No changes.
template
Formats diff output using a Go template string or file (@file, @@ to escape leading @) specified via --template (-T).
--template is required for template mode and cannot be used with other modes.
Sprig template functions (https://masterminds.github.io/sprig/) are available.
Template Variables
Root context (.):
.Left: Left input file name or label (string)..Right: Right input file name or label (string)..HasDiff:trueif differences were found (bool)..Stats: Diff count statistics (DiffStats)..Stats.Add: Count of added objects (int)..Stats.Change: Count of changed objects (int)..Stats.Destroy: Count of destroyed objects (int).
.Diffs: List of diff items ([]*TemplateDiffItem)..ID: Object ID string (e.g.apps/v1>Deployment>default>nginx)..Diff: Unified diff string..DiffType: Diff type ("add","change","destroy")..Left: Left Kubernetes object before changes (ornilif added)..Header.APIVersion:apiVersion(string)..Header.Kind:kind(string)..Header.Metadata.Namespace:metadata.namespace(string)..Header.Metadata.Name:metadata.name(string)..Body: Manifest YAML string (string).
.Right: Right Kubernetes object after changes (ornilif destroyed). Same fields as.Left.
Example (reproducing the default markdown output):
# Objdiff Summary: {{ .Left }} <-> {{ .Right }}
{{ if not .HasDiff -}}
No changes.
{{ else -}}
| **add** | **change** | **destroy** |
| :---: | :---: | :---: |
| {{ .Stats.Add }} | {{ .Stats.Change }} | {{ .Stats.Destroy }} |
{{ range .Diffs }}
<details>
<summary><b>{{ .DiffType }}</b> <code>{{ .ID }}</code></summary>
``` diff
{{ .Diff }}```
</details>
{{ end -}}
{{ end }}
Exit status
0 if inputs are the same. 1 if inputs differ. Otherwise 2.
Filtering
objdiff supports filtering lines, fields, labels, and annotations:
- Line filter (
-i,--ignore-matching-lines): ignores lines matching regular expressions. - Field filter (
-f,--ignore-field): ignores fields by path (e.g.status,metadata.managedFields) or yq deletion expressions (e.g.del(.status)). - Label filter (
-l,--ignore-label): ignores labels across metadata and nested pod templates by key. - Annotation filter (
-a,--ignore-annotation): ignores annotations across metadata and nested pod templates by key. - Shortcut flags:
-m,--ignore-managed-fields: shortcut for-f metadata.managedFields.-s,--ignore-status: shortcut for-f status.
Override differ
objdiff -x diff left.yml right.yml
invokes
diff --unified=3 --color=never --label left.yml --label right.yml LEFT_FILE RIGHT_FILE
OBJDIFF_DIFF_CMD='diff' objdiff -c -C 5 left.yml right.yml
invokes
diff --unified=5 --color=always --label left.yml --label right.yml LEFT_FILE RIGHT_FILE
Configuration & Precedence
Configuration values are resolved in the following order of precedence (highest to lowest):
- Command-line flags (e.g. --diff-cmd)
- Environment variables prefixed with OBJDIFF_ (e.g. OBJDIFF_DIFF_CMD, OBJDIFF_CONTEXT)
- Default values defined for each flag
Environment variables are derived from flag names in uppercase with hyphens replaced by underscores. e.g. --ignore-matching-lines -> OBJDIFF_IGNORE_MATCHING_LINES
Flags
--allow-duplicate-key allow the use of keys with the same name in the same map (default true)
-c, --color colored diff
-C, --context int diff context (default 3)
--debug enable debug log
-x, --diff-cmd string invoke this to get diff instead of builtin differ
-a, --ignore-annotation stringArray ignore annotation by key (may be separated by ';' or specified multiple times)
-f, --ignore-field stringArray ignore field by path or yq expression (may be separated by ';' or specified multiple times)
-l, --ignore-label stringArray ignore label by key (may be separated by ';' or specified multiple times)
-m, --ignore-managed-fields ignore metadata.managedFields
-i, --ignore-matching-lines stringArray ignore lines matching regexp (may be separated by ';' or specified multiple times)
-s, --ignore-status ignore status field
-n, --indent int yaml indent (default 2)
-L, --label stringArray use label instead of file name (may be separated by ';' or specified multiple times)
--markdown-heading uint highest heading level in markdown (default 1)
--markdown-title string title in markdown summary; template variables: LEFT_FILE, RIGHT_FILE (default "Objdiff Summary: {{ .LEFT_FILE }} <-> {{ .RIGHT_FILE }}")
--mcp start MCP server over stdio
-o, --out string output format: text,yaml,id,idlist,markdown,template (default "text")
-q, --quiet quiet log
-d, --separator string object id separator (default ">")
--success exit with 0 even if inputs differ
-T, --template string template string or file (prefix with '@') for template output mode
-v, --verbose enable verbose output; annotate diff type and display summary
--version print objdiff version
Example
For left.yml and right.yml, executing
objdiff left.yml right.yml
yields the result.
Installation
go install github.com/berquerant/k8s-object-diff-go/cmd/objdiff@latest
MCP Server Configuration
You can register objdiff as a Model Context Protocol (MCP) server for AI agents using --mcp.
MCP Settings JSON
{
"mcpServers": {
"objdiff": {
"command": "objdiff",
"args": ["--mcp"]
}
}
}