<?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: Shivam</title>
    <description>The latest articles on DEV Community by Shivam (@shivaggw).</description>
    <link>https://dev.to/shivaggw</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%2F3840969%2Fed0b2c39-d9f3-417e-91e5-eccaaa825baf.png</url>
      <title>DEV Community: Shivam</title>
      <link>https://dev.to/shivaggw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shivaggw"/>
    <language>en</language>
    <item>
      <title>How to Compare package.json Files: A Node.js Developer's Guide</title>
      <dc:creator>Shivam</dc:creator>
      <pubDate>Tue, 21 Apr 2026 14:28:44 +0000</pubDate>
      <link>https://dev.to/shivaggw/how-to-compare-packagejson-files-a-nodejs-developers-guide-3oea</link>
      <guid>https://dev.to/shivaggw/how-to-compare-packagejson-files-a-nodejs-developers-guide-3oea</guid>
      <description>&lt;p&gt;You open a pull request to review a dependency update and the diff is a wall of text — 80 lines of package names and version numbers. Your teammate says "just bumped a few deps", but buried in there is a downgraded React version and two new packages nobody discussed.&lt;/p&gt;

&lt;p&gt;Manually spotting that by eye is error-prone. A proper side-by-side diff would have caught it in seconds.&lt;/p&gt;

&lt;p&gt;Here are four methods for comparing package.json files, when to use each, and a workflow that fits into real code reviews.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why package.json Comparisons Go Wrong
&lt;/h2&gt;

&lt;p&gt;The obvious ones are easy — a new package name sticks out. The dangerous ones are subtle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A minor version bump (&lt;code&gt;^18.2.0 → ^18.3.0&lt;/code&gt;) that pulls in a breaking change via a transitive dependency&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;peerDependency&lt;/code&gt; conflict where two packages need different versions of the same library — causing silent runtime bugs that your test suite won't catch&lt;/li&gt;
&lt;li&gt;A package silently downgraded during a lockfile resolution&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;devDependency&lt;/code&gt; accidentally moved to &lt;code&gt;dependencies&lt;/code&gt;, inflating your production bundle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are obvious from a quick glance at a git diff. They need a proper side-by-side comparison.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 1: Git Diff (Fastest)
&lt;/h2&gt;

&lt;p&gt;The go-to for a quick local check before pushing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff main..feature-branch &lt;span class="nt"&gt;--&lt;/span&gt; package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To include more context lines around each change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;-U10&lt;/span&gt; main..feature-branch &lt;span class="nt"&gt;--&lt;/span&gt; package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always diff the lockfile at the same time — version constraints in package.json can hide transitive changes that only show up in &lt;code&gt;package-lock.json&lt;/code&gt; or &lt;code&gt;yarn.lock&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;git diff main..feature-branch &lt;span class="nt"&gt;--&lt;/span&gt; package.json package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Quick checks before pushing. Not great for large files or sharing with teammates — the raw terminal output is hard to read.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 2: GitHub Pull Request Diff
&lt;/h2&gt;

&lt;p&gt;If the PR is already open on GitHub:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;strong&gt;Files changed&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Scroll to &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click the split view icon (two columns) for side-by-side mode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub highlights added lines in green and removed lines in red. For large files, use the &lt;strong&gt;File filter&lt;/strong&gt; dropdown at the top to jump straight to &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Reviewing a PR before merging. Doesn't help when you want to compare arbitrary branches or files not in an open PR.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 3: Online Diff Tools (Most Visual)
&lt;/h2&gt;

&lt;p&gt;For a detailed, shareable comparison — especially useful for large dependency updates or monorepo audits — paste both &lt;code&gt;package.json&lt;/code&gt; files into an online diff tool like &lt;a href="https://www.online-diff.com" rel="noopener noreferrer"&gt;Online Diff&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's what a typical comparison looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;branch&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^18.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.4.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lodash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.17.21"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;feature&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;branch&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^18.3.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bumped&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.4.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lodash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.17.21"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"zod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.22.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;added&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"date-fns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.0.0"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;added&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With syntax highlighting and character-level diffs, version bumps and new packages are immediately obvious. You can share the diff URL with your team — useful when the reviewer can't run git locally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Detailed dependency audits, sharing with colleagues, comparing files across different repos.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 4: npm diff (npm 8+)
&lt;/h2&gt;

&lt;p&gt;npm 8 introduced a built-in diff command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm diff &lt;span class="nt"&gt;--&lt;/span&gt; package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also compare specific versions of a package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lodash@4.17.20 &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lodash@4.17.21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Comparing installed package versions when investigating what changed between two npm installs. Less useful for branch-to-branch comparisons.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Security Angle: Why This Matters Beyond Code Review
&lt;/h2&gt;

&lt;p&gt;Dependency diffs are one of the most underused parts of a security review. When a new package is added to your project, you're trusting that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The package author hasn't published malicious code&lt;/li&gt;
&lt;li&gt;The package's own dependencies are clean&lt;/li&gt;
&lt;li&gt;The version you're pinning doesn't have a known CVE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A side-by-side diff makes the attack surface visible. When you see "5 new packages added", that's 5 supply chain vectors to evaluate — much easier to spot in a visual diff than buried in 120 lines of JSON.&lt;/p&gt;

&lt;p&gt;After reviewing the diff visually, always run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This cross-references your dependencies against the npm advisory database. A version bump that looks harmless in the diff may resolve — or introduce — a known vulnerability.&lt;/p&gt;




&lt;h2&gt;
  
  
  Handling Monorepos
&lt;/h2&gt;

&lt;p&gt;If you manage multiple &lt;code&gt;package.json&lt;/code&gt; files across a monorepo (&lt;code&gt;apps/web/&lt;/code&gt;, &lt;code&gt;apps/api/&lt;/code&gt;, &lt;code&gt;packages/ui/&lt;/code&gt;), script the extraction:&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;# Extract package.json files from main branch&lt;/span&gt;
git show main:apps/web/package.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; web-main.json
git show main:apps/api/package.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; api-main.json
git show main:packages/ui/package.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ui-main.json

&lt;span class="c"&gt;# Then paste each pair into an online diff tool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how version drift gets caught — where &lt;code&gt;apps/web&lt;/code&gt; is on React 18.2 and &lt;code&gt;packages/ui&lt;/code&gt; is still on React 17, causing subtle incompatibilities that only surface at runtime.&lt;/p&gt;

&lt;p&gt;For automated checks across all packages:&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="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;dir &lt;/span&gt;&lt;span class="k"&gt;in &lt;/span&gt;packages/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== &lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt; ==="&lt;/span&gt;
  git diff main..feature &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;/package.json"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A Real Code Review Workflow
&lt;/h2&gt;

&lt;p&gt;Here's how this fits into a real PR review process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developer opens PR with dependency updates&lt;/li&gt;
&lt;li&gt;CI runs &lt;code&gt;npm audit&lt;/code&gt; — flags any known vulnerabilities&lt;/li&gt;
&lt;li&gt;Reviewer extracts both &lt;code&gt;package.json&lt;/code&gt; versions and pastes into a diff tool&lt;/li&gt;
&lt;li&gt;Reviewer sees at a glance: 2 new packages (zod, date-fns), 1 version bump (react &lt;code&gt;^18.2.0 → ^18.3.0&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Reviewer checks the CHANGELOG for new packages&lt;/li&gt;
&lt;li&gt;Reviewer confirms the React bump is a minor version (safe)&lt;/li&gt;
&lt;li&gt;Approve and merge&lt;/li&gt;
&lt;li&gt;After merge: &lt;code&gt;npm install&lt;/code&gt;, CI tests pass&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This takes 3 minutes. Without the diff, it takes 10 minutes of squinting at JSON, and you're still not confident you caught everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;git diff&lt;/code&gt; for fast local checks before pushing&lt;/li&gt;
&lt;li&gt;Use GitHub's PR view for reviewing changes before merging&lt;/li&gt;
&lt;li&gt;Use an online diff tool for detailed audits and sharing&lt;/li&gt;
&lt;li&gt;Always diff the lockfile alongside &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm audit&lt;/code&gt; after any dependency comparison&lt;/li&gt;
&lt;li&gt;In monorepos, script the extraction to catch version drift across all packages&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;What's your workflow for reviewing dependency changes? Drop it in the comments — always curious how teams handle this at scale.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.online-diff.com/blog/compare-package-json" rel="noopener noreferrer"&gt;online-diff.com/blog/compare-package-json&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>webdev</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
