<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: sdkks</title>
    <description>The latest articles on DEV Community by sdkks (@sdkks).</description>
    <link>https://dev.to/sdkks</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3903697%2F969d6855-bf54-4b88-909c-771fec3d32a4.png</url>
      <title>DEV Community: sdkks</title>
      <link>https://dev.to/sdkks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sdkks"/>
    <language>en</language>
    <item>
      <title>nesdit: Targeted In-Place Edits for JSON, YAML, and TOML with jq-Style Queries</title>
      <dc:creator>sdkks</dc:creator>
      <pubDate>Wed, 29 Apr 2026 11:05:09 +0000</pubDate>
      <link>https://dev.to/sdkks/nesdit-targeted-in-place-edits-for-json-yaml-and-toml-with-jq-style-queries-3i66</link>
      <guid>https://dev.to/sdkks/nesdit-targeted-in-place-edits-for-json-yaml-and-toml-with-jq-style-queries-3i66</guid>
      <description>&lt;p&gt;You know what you want to do. You want to set one value in a config file. The problem is finding it — three levels deep in a YAML you didn't write, in a key named something slightly different from what you expected, in a file that's 400 lines long and growing. So you open it in an editor, search, scroll, edit, save. It works. Then you need to do it again in CI, on a different file, with a value that comes from an environment variable. Now it's a shell script. Now it's fragile.&lt;/p&gt;

&lt;p&gt;The deeper frustration isn't the individual file. It's that the moment you want to go slightly further — preview what would change before writing, confirm a file is already at the right value, apply the same change across a stream of Kubernetes manifests — you hit the ceiling of whatever tool you're using. &lt;code&gt;jq&lt;/code&gt; is JSON-only and has no in-place flag. &lt;code&gt;yq&lt;/code&gt; handles YAML but can't write TOML and gives you no way to detect drift. You end up gluing three tools together with shell, and the glue breaks in ways that are hard to test and harder to debug.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nesdit&lt;/code&gt; takes a different approach: one binary, one query syntax (jq-style, so you already know it), three formats. You describe what the document &lt;em&gt;should look like&lt;/em&gt; — not how to get there. nesdit applies it, shows you a diff if you want one, tells you via exit code whether anything actually changed, and writes atomically if you say so. The same command that edits one file in your terminal gates a CI step, validates a stream of manifests, or updates a batch of configs — without any shell glue in between.&lt;/p&gt;




&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Go&lt;/span&gt;
go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/sdkks/nesdit/cmd/nesdit@latest

&lt;span class="c"&gt;# Homebrew&lt;/span&gt;
brew tap sdkks/tap &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;sdkks/tap/nesdit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pre-built binaries (Linux amd64/arm64, macOS arm64) are on the &lt;a href="https://github.com/sdkks/nesdit/releases" rel="noopener noreferrer"&gt;releases page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Basics
&lt;/h2&gt;

&lt;p&gt;nesdit reads a file (or stdin), applies a jq-style query, and writes the result. Format is auto-detected from the file extension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Print to stdout — file untouched&lt;/span&gt;
nesdit config.json &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.env = "production"'&lt;/span&gt;

&lt;span class="c"&gt;# Edit in-place (atomic write via temp file + rename)&lt;/span&gt;
nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; config.json &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.env = "production"'&lt;/span&gt;

&lt;span class="c"&gt;# Preview changes without writing (unified diff to stdout)&lt;/span&gt;
nesdit &lt;span class="nt"&gt;-n&lt;/span&gt; config.json &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.env = "production"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same flags work for YAML and TOML — no format-specific commands to remember.&lt;/p&gt;




&lt;h2&gt;
  
  
  JSON: Key Order Preserved, Compact Output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"env":"staging","replicas":1,"debug":false}'&lt;/span&gt; | nesdit &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.env = "production" | .replicas = 3'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"env"&lt;/span&gt;:&lt;span class="s2"&gt;"production"&lt;/span&gt;,&lt;span class="s2"&gt;"replicas"&lt;/span&gt;:3,&lt;span class="s2"&gt;"debug"&lt;/span&gt;:false&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key order is preserved — &lt;code&gt;env&lt;/code&gt; stays first, &lt;code&gt;debug&lt;/code&gt; stays last. nesdit always outputs compact JSON (no newlines between keys). If you hand it pretty-printed JSON it comes back compact — that's the current behaviour, worth knowing before you run it on a formatted file.&lt;/p&gt;

&lt;p&gt;Compare with jq, which always pretty-prints by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"env":"staging","replicas":1}'&lt;/span&gt; | jq &lt;span class="s1"&gt;'.env = "production"'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"env"&lt;/span&gt;: &lt;span class="s2"&gt;"production"&lt;/span&gt;,
  &lt;span class="s2"&gt;"replicas"&lt;/span&gt;: 1
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And jq has no &lt;code&gt;-i&lt;/code&gt; flag — in-place editing requires the workaround:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'.env = "production"'&lt;/span&gt; config.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; tmp.json &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mv &lt;/span&gt;tmp.json config.json
&lt;span class="c"&gt;# If jq fails, tmp.json is empty and the original is gone.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;nesdit's &lt;code&gt;-i&lt;/code&gt; writes atomically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; config.json &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.env = "production"'&lt;/span&gt;
&lt;span class="c"&gt;# Atomic: temp file in same dir → rename over target.&lt;/span&gt;
&lt;span class="c"&gt;# On failure: original is untouched.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  YAML: Key Order Preserved, Merge Keys Work
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# values.yaml&lt;/span&gt;
&lt;span class="na"&gt;zebra&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;z-value&lt;/span&gt;
&lt;span class="na"&gt;apple&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;a-value&lt;/span&gt;
&lt;span class="na"&gt;mango&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;m-value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nesdit values.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.apple = "updated"'&lt;/span&gt;
zebra: z-value
apple: updated
mango: m-value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key order is preserved exactly. This matters when you're diffing manifests and don't want spurious reordering in the git log.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anchor merge keys (&lt;code&gt;&amp;lt;&amp;lt;:&lt;/code&gt;) are applied at decode time
&lt;/h3&gt;

&lt;p&gt;As of v0.3.2, nesdit correctly applies YAML merge keys. This is particularly useful for Helm values files and Kubernetes configs that use anchors for shared defaults:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config.yaml&lt;/span&gt;
&lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;defaults&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;

&lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*defaults&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nesdit config.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.web.image = "nginx:1.25"'&lt;/span&gt;
defaults:
  replicas: 1
  image: nginx
web:
  replicas: 3
  image: nginx:1.25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;lt;&amp;lt;:&lt;/code&gt; merge is resolved at decode — &lt;code&gt;web.image&lt;/code&gt; is accessible and writable. The &lt;code&gt;&amp;lt;&amp;lt;:&lt;/code&gt; key does not appear in the output.&lt;/p&gt;

&lt;h3&gt;
  
  
  What nesdit doesn't preserve in YAML
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Comments and quoted strings&lt;/strong&gt; are both stripped during the parse-serialize cycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# input&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
&lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;   &lt;span class="c1"&gt;# scale this&lt;/span&gt;
&lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100m"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nesdit input.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.replicas = 3'&lt;/span&gt;
name: myapp
replicas: 3
cpu: 100m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The comment is gone. The quotes on &lt;code&gt;cpu&lt;/code&gt; are gone. This is consistent with how most YAML parsers behave — the YAML spec treats &lt;code&gt;100m&lt;/code&gt; and &lt;code&gt;"100m"&lt;/code&gt; as the same string value. If your workflow depends on comment preservation, nesdit is not the right tool for that file.&lt;/p&gt;

&lt;p&gt;For files without comments — which is the majority of machine-managed config and Kubernetes manifests — nesdit's output is clean and minimal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# deploy.yaml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
&lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.24&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; deploy.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.replicas = 3 | .image = "nginx:1.25"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# deploy.yaml after&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
&lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.25&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the touched values changed.&lt;/p&gt;




&lt;h2&gt;
  
  
  TOML: Write Support (Flat Keys Work Best)
&lt;/h2&gt;

&lt;p&gt;This is where the ecosystem gap is most obvious. &lt;code&gt;yq&lt;/code&gt; (mikefarah) can read TOML but explicitly cannot write it back. &lt;code&gt;kislyuk/yq&lt;/code&gt;'s &lt;code&gt;tomlq&lt;/code&gt; drops comments. &lt;code&gt;dasel&lt;/code&gt; strips explicit string quotes.&lt;/p&gt;

&lt;p&gt;nesdit can write TOML. For &lt;strong&gt;flat (no-section) TOML&lt;/strong&gt;, it preserves key order and only changes the targeted value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# config.toml&lt;/span&gt;
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"project"&lt;/span&gt;
&lt;span class="py"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nesdit config.toml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.version = "2.0"'&lt;/span&gt;
version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2.0"&lt;/span&gt;
name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"project"&lt;/span&gt;
debug &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;strong&gt;sectioned TOML&lt;/strong&gt; (&lt;code&gt;[package]&lt;/code&gt; style), nesdit currently rewrites sections to inline-table syntax — this is a known trade-off documented in the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# input: Cargo.toml&lt;/span&gt;
&lt;span class="nn"&gt;[package]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-crate"&lt;/span&gt;
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;

&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;tokio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nesdit Cargo.toml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.package.version = "0.2.0"'&lt;/span&gt;
package &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-crate"&lt;/span&gt;, version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
dependencies &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;tokio &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Semantically correct, structurally different. The inline-table form guarantees stable round-trips regardless of key order — but it is not idiomatic for &lt;code&gt;Cargo.toml&lt;/code&gt; or &lt;code&gt;pyproject.toml&lt;/code&gt;. For flat TOML configs (&lt;code&gt;version = "x"&lt;/code&gt; style) it works cleanly. For sectioned TOML, wait for a future release or file a request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Human-readable TOML output with &lt;code&gt;--pretty&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;--pretty&lt;/code&gt; flag emits TOML with blank lines between top-level entries and multi-line arrays:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"myapp","tags":["go","toml","cli"]}\n'&lt;/span&gt; | nesdit &lt;span class="nt"&gt;--format&lt;/span&gt; json &lt;span class="nt"&gt;--output-format&lt;/span&gt; toml &lt;span class="nt"&gt;--pretty&lt;/span&gt;
name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"myapp"&lt;/span&gt;

tags &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="s2"&gt;"go"&lt;/span&gt;,
  &lt;span class="s2"&gt;"toml"&lt;/span&gt;,
  &lt;span class="s2"&gt;"cli"&lt;/span&gt;,
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--pretty&lt;/code&gt; is silently ignored for JSON and YAML output.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dry-Run and Drift Check: The CI/CD Workflow
&lt;/h2&gt;

&lt;p&gt;This is where nesdit earns its place in a pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;--dry-run&lt;/code&gt; (&lt;code&gt;-n&lt;/code&gt;): preview before writing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nesdit &lt;span class="nt"&gt;-n&lt;/span&gt; helm/values.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.image.tag = "v2.0.0"'&lt;/span&gt;
&lt;span class="nt"&gt;---&lt;/span&gt; helm/values.yaml
+++ helm/values.yaml
@@ &lt;span class="nt"&gt;-1&lt;/span&gt;,6 +1,6 @@
 image:
   repository: nginx
-  tag: v1.9.0
+  tag: v2.0.0
   pullPolicy: IfNotPresent
 service:
   port: 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exits &lt;code&gt;0&lt;/code&gt; whether or not there's a diff. Use this in CI to log what a release would change before actually changing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;--check&lt;/code&gt;: gate on drift via exit code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nesdit &lt;span class="nt"&gt;--check&lt;/span&gt; config/values.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.image.tag = "v2.0.0"'&lt;/span&gt;
&lt;span class="c"&gt;# Exit 0 — already up to date&lt;/span&gt;
&lt;span class="c"&gt;# Exit 1 — error (parse failure, bad query, etc.)&lt;/span&gt;
&lt;span class="c"&gt;# Exit 2 — would change (drift detected)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exit code &lt;code&gt;2&lt;/code&gt; is reserved exclusively for drift, making it safe to branch on in scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nesdit &lt;span class="nt"&gt;--check&lt;/span&gt; helm/values.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.image.tag = "v2.0.0"'&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="k"&gt;in
  &lt;/span&gt;0&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Already at v2.0.0, nothing to do"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  2&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Drift — applying update"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; helm/values.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.image.tag = "v2.0.0"'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1 &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="k"&gt;esac&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neither &lt;code&gt;yq&lt;/code&gt; nor &lt;code&gt;jq&lt;/code&gt; provides this — you'd have to extract the value, compare it in shell, and then run the edit as a separate step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-commit hook
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .pre-commit-hooks.yaml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nesdit-check&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Detect config drift&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nesdit --check --query '.'&lt;/span&gt;
  &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^config/.*\.(yaml|json|toml)$&lt;/span&gt;
  &lt;span class="na"&gt;pass_filenames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the identity query (&lt;code&gt;.&lt;/code&gt;) against committed config files. If someone hand-edits a file in a way that would change its canonical form, the hook catches it before the commit lands.&lt;/p&gt;




&lt;h2&gt;
  
  
  Multi-Document YAML via Stdin
&lt;/h2&gt;

&lt;p&gt;Kubernetes manifests are often multi-document YAML — multiple resources in one file, separated by &lt;code&gt;---&lt;/code&gt;. nesdit handles multi-doc YAML in &lt;strong&gt;stdin stream mode&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;manifests.yaml | nesdit &lt;span class="nt"&gt;--format&lt;/span&gt; yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--where&lt;/span&gt; &lt;span class="s1"&gt;'.kind == "Deployment"'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.spec.replicas = 3'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--where&lt;/code&gt; flag applies your query only to documents matching the predicate. Non-matching documents (like Services) pass through unchanged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input (&lt;code&gt;manifests.yaml&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend:v1.0&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend:v1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Command:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;manifests.yaml | nesdit &lt;span class="nt"&gt;--format&lt;/span&gt; yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--where&lt;/span&gt; &lt;span class="s1"&gt;'.kind == "Deployment" and .metadata.name == "frontend"'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.spec.template.spec.containers[0].image = "frontend:v2.0"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend:v2.0&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend:v1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the frontend Deployment was touched. The Service and backend Deployment are byte-for-byte identical.&lt;/p&gt;

&lt;p&gt;Note: &lt;code&gt;nesdit -i manifests.yaml&lt;/code&gt; only supports single-document YAML — multi-doc requires stdin. To write multi-doc edits back to a file, redirect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;manifests.yaml | nesdit &lt;span class="nt"&gt;--format&lt;/span&gt; yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--where&lt;/span&gt; &lt;span class="s1"&gt;'.kind == "Deployment"'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.spec.replicas = 3'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; manifests.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Shell Variable Injection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;--arg&lt;/code&gt;: string values
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"v2.0.0"&lt;/span&gt;
nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; values.yaml &lt;span class="nt"&gt;--arg&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.image.tag = $version'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--arg&lt;/code&gt; always binds as a string. Numbers passed this way stay strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;--argjson&lt;/code&gt;: typed values
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; deploy.yaml &lt;span class="nt"&gt;--argjson&lt;/span&gt; &lt;span class="nv"&gt;replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.spec.replicas = $replicas'&lt;/span&gt;
&lt;span class="c"&gt;# .spec.replicas becomes the number 5, not the string "5"&lt;/span&gt;

nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; config.yaml &lt;span class="nt"&gt;--argjson&lt;/span&gt; &lt;span class="nv"&gt;enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.feature.enabled = $enabled'&lt;/span&gt;
&lt;span class="c"&gt;# boolean&lt;/span&gt;

nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; config.yaml &lt;span class="nt"&gt;--argjson&lt;/span&gt; &lt;span class="nv"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'["web","api"]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create-missing&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.service.tags = $tags'&lt;/span&gt;
&lt;span class="c"&gt;# array&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--argjson&lt;/code&gt; parses the value as JSON — numbers, booleans, arrays, and objects all work. If the value isn't valid JSON, nesdit exits with a clear error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nesdit config.json &lt;span class="nt"&gt;--argjson&lt;/span&gt; &lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'not-json'&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.v = $v'&lt;/span&gt;
nesdit: error: arg.decode: &lt;span class="nt"&gt;--argjson&lt;/span&gt; v: expected JSON, got &lt;span class="s2"&gt;"not-json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Batch Updates
&lt;/h2&gt;

&lt;p&gt;Pass multiple files to update them all in one run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; config/a.yaml config/b.yaml config/c.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.replicas = 5'&lt;/span&gt;
&lt;span class="c"&gt;# nesdit: info: batch.summary: 3 changed, 0 unchanged, 0 errored&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default (&lt;code&gt;--strict&lt;/code&gt;), if any file fails, &lt;strong&gt;nothing is written&lt;/strong&gt;. This is the safe default for pipelines where partial updates are worse than no update.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;--keep-going&lt;/code&gt; to process all files and report errors at the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nesdit &lt;span class="nt"&gt;-i&lt;/span&gt; config/&lt;span class="k"&gt;*&lt;/span&gt;.yaml &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.replicas = 5'&lt;/span&gt; &lt;span class="nt"&gt;--keep-going&lt;/span&gt;
&lt;span class="c"&gt;# nesdit: error: config/broken.yaml: query.runtime: ...&lt;/span&gt;
&lt;span class="c"&gt;# nesdit: info: batch.summary: 4 changed, 0 unchanged, 1 errored&lt;/span&gt;
&lt;span class="c"&gt;# Exit code: 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A Complete CI/CD Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/release.yml&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;v*'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;bump-chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install nesdit&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go install github.com/sdkks/nesdit/cmd/nesdit@latest&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Preview change&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;nesdit helm/values.yaml -n \&lt;/span&gt;
            &lt;span class="s"&gt;--arg tag="${{ github.ref_name }}" \&lt;/span&gt;
            &lt;span class="s"&gt;--query '.image.tag = $tag'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check if already current&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drift&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;nesdit helm/values.yaml --check \&lt;/span&gt;
            &lt;span class="s"&gt;--arg tag="${{ github.ref_name }}" \&lt;/span&gt;
            &lt;span class="s"&gt;--query '.image.tag = $tag'&lt;/span&gt;
          &lt;span class="s"&gt;echo "exit=$?" &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;
        &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Apply and commit&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;steps.drift.outputs.exit == '2'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;nesdit -i helm/values.yaml \&lt;/span&gt;
            &lt;span class="s"&gt;--arg tag="${{ github.ref_name }}" \&lt;/span&gt;
            &lt;span class="s"&gt;--query '.image.tag = $tag'&lt;/span&gt;
          &lt;span class="s"&gt;git config user.name "release-bot"&lt;/span&gt;
          &lt;span class="s"&gt;git config user.email "bot@example.com"&lt;/span&gt;
          &lt;span class="s"&gt;git add helm/values.yaml&lt;/span&gt;
          &lt;span class="s"&gt;git commit -m "chore: bump image tag to ${{ github.ref_name }}"&lt;/span&gt;
          &lt;span class="s"&gt;git push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three steps: preview (log what changes), check (skip commit if already current), apply (one clean diff). The &lt;code&gt;--arg&lt;/code&gt; injection avoids shell-quoting issues around the tag value.&lt;/p&gt;




&lt;h2&gt;
  
  
  Format Transcoding
&lt;/h2&gt;

&lt;p&gt;nesdit can read one format and write another with &lt;code&gt;--output-format&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# JSON → YAML&lt;/span&gt;
nesdit config.json &lt;span class="nt"&gt;--output-format&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; config.yaml

&lt;span class="c"&gt;# YAML → JSON&lt;/span&gt;
nesdit values.yaml &lt;span class="nt"&gt;--output-format&lt;/span&gt; json
&lt;span class="c"&gt;# {"name":"alice","version":1}&lt;/span&gt;

&lt;span class="c"&gt;# YAML → TOML&lt;/span&gt;
nesdit values.yaml &lt;span class="nt"&gt;--output-format&lt;/span&gt; toml
&lt;span class="c"&gt;# name = "alice"&lt;/span&gt;
&lt;span class="c"&gt;# version = 1&lt;/span&gt;

&lt;span class="c"&gt;# TOML → JSON&lt;/span&gt;
nesdit config.toml &lt;span class="nt"&gt;--output-format&lt;/span&gt; json &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'.package'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When transcoding to TOML with multiple input documents (from JSONL or multi-doc YAML stdin), nesdit separates output documents with &lt;code&gt;+++&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'{"a":1}\n{"b":2}\n'&lt;/span&gt; | nesdit &lt;span class="nt"&gt;--format&lt;/span&gt; jsonl &lt;span class="nt"&gt;--output-format&lt;/span&gt; toml
a &lt;span class="o"&gt;=&lt;/span&gt; 1
+++
b &lt;span class="o"&gt;=&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;--output-format&lt;/code&gt; and &lt;code&gt;-i&lt;/code&gt; are mutually exclusive — writing a different format back into the same file would silently corrupt it. Pipe to a new file instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Compares
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;nesdit&lt;/th&gt;
&lt;th&gt;jq&lt;/th&gt;
&lt;th&gt;yq (mikefarah)&lt;/th&gt;
&lt;th&gt;dasel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TOML write&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key order preserved&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comment preservation&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YAML merge keys (&lt;code&gt;&amp;lt;&amp;lt;:&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atomic in-place write&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ (workaround)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dry-run diff&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drift check (exit code)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-doc YAML + &lt;code&gt;--where&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅ (stdin)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jq query syntax&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;mostly&lt;/td&gt;
&lt;td&gt;different&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single binary&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Where to use each tool:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;jq&lt;/strong&gt;: JSON transformation and data extraction pipelines. Nothing beats it for raw JSON power.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;yq&lt;/strong&gt;: YAML-heavy workflows, especially when you need XML, CSV, or properties format support, or full multi-doc file editing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dasel&lt;/strong&gt;: Unified selector syntax if you prefer one query language across all formats.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nesdit&lt;/strong&gt;: Targeted field edits in CI/CD pipelines, especially when you want &lt;code&gt;--check&lt;/code&gt; drift detection or &lt;code&gt;--dry-run&lt;/code&gt; preview before writing. Also the only option for TOML write support with a jq query syntax.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Safety Under Adversarial Inputs
&lt;/h2&gt;

&lt;p&gt;nesdit ships with per-run resource caps by default:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Override&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input size&lt;/td&gt;
&lt;td&gt;10 MiB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--max-bytes 0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Document nesting depth&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--max-depth 0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YAML alias expansion&lt;/td&gt;
&lt;td&gt;100,000 nodes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--max-yaml-nodes 0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query file size&lt;/td&gt;
&lt;td&gt;1 MiB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--max-query-bytes 0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The YAML alias cap mitigates billion-laughs attacks — a crafted YAML file that expands exponentially during parsing. All limits are enforced before the query runs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Find It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/sdkks/nesdit" rel="noopener noreferrer"&gt;https://github.com/sdkks/nesdit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs&lt;/strong&gt;: &lt;a href="https://sdkks.github.io/nesdit" rel="noopener noreferrer"&gt;https://sdkks.github.io/nesdit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Current release&lt;/strong&gt;: v0.3.2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project is in active development. If you hit an edge case — especially around TOML section formatting, comment handling, or a query behaviour that differs from jq — opening an issue with a minimal reproduction is the most useful contribution. Feature requests and PRs welcome.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>cli</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
