<?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: Sulthon Zainul Habib</title>
    <description>The latest articles on DEV Community by Sulthon Zainul Habib (@sulthonzh).</description>
    <link>https://dev.to/sulthonzh</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%2F193370%2Fcec777a0-1651-49a8-88f6-effc00ffaad7.png</url>
      <title>DEV Community: Sulthon Zainul Habib</title>
      <link>https://dev.to/sulthonzh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sulthonzh"/>
    <language>en</language>
    <item>
      <title>I Replaced 70MB Node.js Log Viewer with a 172KB Zig Binary</title>
      <dc:creator>Sulthon Zainul Habib</dc:creator>
      <pubDate>Sun, 24 May 2026 19:21:56 +0000</pubDate>
      <link>https://dev.to/sulthonzh/i-replaced-70mb-nodejs-log-viewer-with-a-172kb-zig-binary-5bn7</link>
      <guid>https://dev.to/sulthonzh/i-replaced-70mb-nodejs-log-viewer-with-a-172kb-zig-binary-5bn7</guid>
      <description>&lt;p&gt;Log files are the debugging reality of production systems. You stare at them daily, curse the noise, and grep until your eyes bleed.&lt;/p&gt;

&lt;p&gt;The problem? Most log viewers are heavy, slow, or require complex setups. I wanted something that just works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;I tried the usual suspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;tail -f&lt;/strong&gt;: Raw, unfiltered stream. No filtering, no highlighting. Useless for anything beyond watching errors fly by.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;grep&lt;/strong&gt;: Powerful but terminal-destroying. &lt;code&gt;grep -R "ERROR" ./logs | grep "database"&lt;/code&gt; works, but it's not interactive. You can't drill down, and the output is a wall of text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker logs&lt;/strong&gt;: &lt;code&gt;docker logs -f container&lt;/code&gt; is okay for one container, but when you have 15 microservices, it's a mess.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Existing log viewers&lt;/strong&gt;: Most are GUI apps (heavy), or Node.js CLI tools (slow, 70MB+ dependencies), or require configuration files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I needed something that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is &lt;strong&gt;fast&lt;/strong&gt; — no lag when scrolling through 1GB log files&lt;/li&gt;
&lt;li&gt;Has &lt;strong&gt;syntax highlighting&lt;/strong&gt; — ERROR in red, DEBUG in gray, stack traces visible&lt;/li&gt;
&lt;li&gt;Lets me &lt;strong&gt;filter interactively&lt;/strong&gt; — type &lt;code&gt;/&lt;/code&gt; to search, drill down without re-running commands&lt;/li&gt;
&lt;li&gt;Is &lt;strong&gt;tiny&lt;/strong&gt; — no 70MB node_modules bloat&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Solution: logchef-zig
&lt;/h2&gt;

&lt;p&gt;I wrote logchef-zig in Zig. It's a single 172KB binary that does exactly what I need:&lt;/p&gt;

&lt;h3&gt;
  
  
  What It Does
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# View any log file with auto-highlighting&lt;/span&gt;
logchef app.log

&lt;span class="c"&gt;# Follow mode (like tail -f, but with filtering)&lt;/span&gt;
logchef &lt;span class="nt"&gt;-f&lt;/span&gt; app.log

&lt;span class="c"&gt;# Filter by log level before opening&lt;/span&gt;
logchef &lt;span class="nt"&gt;--level&lt;/span&gt; error app.log

&lt;span class="c"&gt;# Interactive search (press / inside the viewer)&lt;/span&gt;
logchef app.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Zig?
&lt;/h3&gt;

&lt;p&gt;I chose Zig for three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Zero dependencies&lt;/strong&gt;: No node_modules, no Python runtime, nothing. Just one binary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Zig compiles to native machine code. I'm talking instant scrolling on 1GB+ files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-compilation&lt;/strong&gt;: I can build for Linux, macOS, and Windows from my Mac. One CI run, three binaries.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;h3&gt;
  
  
  1. Fast Log Parsing
&lt;/h3&gt;

&lt;p&gt;Logchef reads logs line-by-line and detects common log formats automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;2026-05-25T02:19:12.123Z [INFO] User logged in
2026-05-25T02:19:15.456Z [ERROR] Database connection failed
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It extracts timestamps, log levels, and context, then applies syntax highlighting.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Interactive TUI
&lt;/h3&gt;

&lt;p&gt;The interface is terminal-based (like htop or lazygit):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arrow keys&lt;/strong&gt;: Scroll through the file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/&lt;/code&gt;&lt;/strong&gt;: Search for patterns (supports regex)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;l&lt;/code&gt;&lt;/strong&gt;: Filter by log level (DEBUG, INFO, WARN, ERROR)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;q&lt;/code&gt;&lt;/strong&gt;: Quit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No mouse required. Pure keyboard efficiency.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Zero Configuration
&lt;/h3&gt;

&lt;p&gt;Logchef doesn't need a config file. It detects log patterns heuristically. If your logs look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[INFO] Something happened
ERROR: Something broke
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It just works. If they don't, you can pass a custom regex.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks
&lt;/h2&gt;

&lt;p&gt;I tested logchef against a 1GB log file with 10 million lines:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Startup Time&lt;/th&gt;
&lt;th&gt;Memory Usage&lt;/th&gt;
&lt;th&gt;Binary Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;logchef-zig&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.05s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.5MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;172KB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js equivalent&lt;/td&gt;
&lt;td&gt;1.2s&lt;/td&gt;
&lt;td&gt;85MB&lt;/td&gt;
&lt;td&gt;70MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bat (syntax highlighter)&lt;/td&gt;
&lt;td&gt;0.8s&lt;/td&gt;
&lt;td&gt;12MB&lt;/td&gt;
&lt;td&gt;4.2MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cat (no highlighting)&lt;/td&gt;
&lt;td&gt;0.01s&lt;/td&gt;
&lt;td&gt;0.5MB&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Scrolling is instant. No lag. No beach balls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Debugging Production Issues
&lt;/h3&gt;

&lt;p&gt;You get paged at 2 AM. A service is failing.&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;# SSH into the server&lt;/span&gt;
ssh production-server

&lt;span class="c"&gt;# Start following the logs&lt;/span&gt;
logchef &lt;span class="nt"&gt;-f&lt;/span&gt; /var/log/app/app.log

&lt;span class="c"&gt;# Press `/` and type "ERROR" to filter only errors&lt;/span&gt;
&lt;span class="c"&gt;# Press `l` to switch to error-only view&lt;/span&gt;
&lt;span class="c"&gt;# Use arrow keys to scroll through the error context&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You find the root cause in 30 seconds instead of 10 minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local Development
&lt;/h3&gt;

&lt;p&gt;You're running a dev server and want to see errors only:&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;# Run your server in background&lt;/span&gt;
npm run dev &amp;amp;

&lt;span class="c"&gt;# Follow logs, error-only&lt;/span&gt;
logchef &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;--level&lt;/span&gt; error logs/combined.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CI/CD Debugging
&lt;/h3&gt;

&lt;p&gt;Your CI pipeline failed. You download the log artifact:&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;# CI artifact downloaded to build.log&lt;/span&gt;
logchef build.log

&lt;span class="c"&gt;# Search for the first error&lt;/span&gt;
/ ERROR

&lt;span class="c"&gt;# Jump to that line, scroll to see context&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;macOS / Linux (Homebrew):&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;brew &lt;span class="nb"&gt;install &lt;/span&gt;sulthonzh/tap/logchef
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Manual download:&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="c"&gt;# Download from GitHub Releases&lt;/span&gt;
wget https://github.com/sulthonzh/logchef-zig/releases/latest/download/logchef-macos-arm64
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x logchef-macos-arm64
&lt;span class="nb"&gt;mv &lt;/span&gt;logchef-macos-arm64 /usr/local/bin/logchef
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;From source:&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="c"&gt;# Requires Zig 0.13+&lt;/span&gt;
git clone https://github.com/sulthonzh/logchef-zig.git
&lt;span class="nb"&gt;cd &lt;/span&gt;logchef-zig
zig build &lt;span class="nt"&gt;-Doptimize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ReleaseSafe
zig build &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# View a log file&lt;/span&gt;
logchef app.log

&lt;span class="c"&gt;# Follow mode (live updates)&lt;/span&gt;
logchef &lt;span class="nt"&gt;-f&lt;/span&gt; app.log

&lt;span class="c"&gt;# Filter by log level&lt;/span&gt;
logchef &lt;span class="nt"&gt;--level&lt;/span&gt; error app.log
logchef &lt;span class="nt"&gt;--level&lt;/span&gt; debug app.log

&lt;span class="c"&gt;# Search inside the viewer (press /)&lt;/span&gt;
logchef app.log
&lt;span class="c"&gt;# Press /, type pattern, enter&lt;/span&gt;
&lt;span class="c"&gt;# Use n/N for next/previous match&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I'm planning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom log format parsing (via CLI flags)&lt;/li&gt;
&lt;li&gt;Log aggregation (multiple files at once)&lt;/li&gt;
&lt;li&gt;Time-range filtering (&lt;code&gt;logchef --from "2h ago" --to "now" app.log&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But even in its current form, logchef-zig has replaced grep and tail for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/sulthonzh/logchef-zig" rel="noopener noreferrer"&gt;https://github.com/sulthonzh/logchef-zig&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install: &lt;code&gt;brew install sulthonzh/tap/logchef&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built with Zig. No dependencies. Just logs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>zig</category>
      <category>performance</category>
      <category>cli</category>
      <category>devtools</category>
    </item>
    <item>
      <title>I Turned npm outdated into a CI Gate — Here's How</title>
      <dc:creator>Sulthon Zainul Habib</dc:creator>
      <pubDate>Sun, 24 May 2026 17:20:15 +0000</pubDate>
      <link>https://dev.to/sulthonzh/i-turned-npm-outdated-into-a-ci-gate-heres-how-h0o</link>
      <guid>https://dev.to/sulthonzh/i-turned-npm-outdated-into-a-ci-gate-heres-how-h0o</guid>
      <description>&lt;p&gt;You run &lt;code&gt;npm outdated&lt;/code&gt; and see a list of stale packages. But your CI doesn't care. It passes anyway. Dependencies drift until something explodes in production. There's no built-in way to fail the build when versions drift too far.## The Problem&lt;code&gt;npm outdated&lt;/code&gt; lists outdated dependencies, but:- No exit codes — CI cannot gate builds on the result- No threshold configuration — you can't say "fail if &amp;gt;2 minors behind"- No distinction between prod and dev dependencies in many workflows- Manual updates become a fire drill instead of a controlled processA typical scenario: Your team wants to stay current with security patches, but you can't update everything. You need a rule: "No production dependency more than 2 minor versions behind latest." &lt;code&gt;npm outdated&lt;/code&gt; can't enforce that.## The SolutionI built &lt;code&gt;npm-outdated-check&lt;/code&gt; to turn &lt;code&gt;npm outdated&lt;/code&gt; into a first-class CI citizen with:- Semantic version thresholding (major/minor/patch drift limits)- Meaningful exit codes (0 = pass, 1 = violation, 2 = config error, 3 = network error)- Configurable via CLI flags or a &lt;code&gt;.npm-outdated-check.json&lt;/code&gt; config file- Production/dev dependency filtering- Multiple output formats (text, table, JSON)## How It WorksThe tool reads your &lt;code&gt;package.json&lt;/code&gt;, queries the npm registry for each dependency, calculates the semantic version difference, and flags anything that exceeds your thresholds.Key implementation details:1. &lt;strong&gt;Registry fetching&lt;/strong&gt;: Hit the npm registry endpoint for each package and extract the &lt;code&gt;dist-tags.latest&lt;/code&gt; version2. &lt;strong&gt;Semver diff&lt;/strong&gt;: Use &lt;code&gt;semver&lt;/code&gt; to parse &lt;code&gt;coerce(current)&lt;/code&gt; and &lt;code&gt;parse(latest)&lt;/code&gt;, then compute &lt;code&gt;major/minor/patch&lt;/code&gt; differences3. &lt;strong&gt;Violation logic&lt;/strong&gt;: A package violates if any diff exceeds its configured &lt;code&gt;maxMajor&lt;/code&gt;/&lt;code&gt;maxMinor&lt;/code&gt;/&lt;code&gt;maxPatch&lt;/code&gt;4. &lt;strong&gt;Exit codes&lt;/strong&gt;: CI reads the exit code and fails the build when violations existSample threshold calculation:&lt;br&gt;
&lt;br&gt;
&lt;code&gt;typescriptconst majorDiff = latest.major - current.major;const minorDiff = latest.minor - current.minor;const patchDiff = latest.patch - current.patch;const isViolation =  majorDiff &amp;gt; config.maxMajor ||  minorDiff &amp;gt; config.minorDiff ||  patchDiff &amp;gt; config.maxPatch;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting StartedInstall globally or as a dev dependency:
&lt;/h2&gt;

&lt;p&gt;&lt;br&gt;
&lt;code&gt;bashnpm install -D npm-outdated-check&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
Run it in CI with sensible defaults (major=0, minor=2, patch=5):&lt;br&gt;
&lt;br&gt;
&lt;code&gt;bashnpx npm-outdated-check&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
Add it to GitHub Actions:&lt;br&gt;
&lt;br&gt;
&lt;code&gt;yamlname: Dependency Checkon: [push, pull_request]jobs:  outdated-check:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-node@v4        with:          node-version: '18'      - run: npm install      - run: npx npm-outdated-check --max-minor 3&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
If a dependency is 4 minor versions behind, CI fails and you get notified.## Why This Matters- &lt;strong&gt;Controlled updates&lt;/strong&gt;: Set thresholds to avoid surprise breaking changes- &lt;strong&gt;Security posture&lt;/strong&gt;: Enforce staying within N patch versions of latest- &lt;strong&gt;Team consistency&lt;/strong&gt;: Config rules checked automatically in CI- &lt;strong&gt;Zero config&lt;/strong&gt;: Works out of the box with smart defaults## What's NextRoadmap items include:- Configurable notification channels (Slack, email)- Automated PR generation for outdated packages- Support for Yarn and pnpm lockfiles- Monorepo workspace awareness## Links- GitHub: &lt;a href="https://github.com/sulthonzh/npm-outdated-check-" rel="noopener noreferrer"&gt;https://github.com/sulthonzh/npm-outdated-check-&lt;/a&gt; Try it: &lt;code&gt;npm install -D npm-outdated-check&lt;/code&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>ci</category>
      <category>devtools</category>
    </item>
    <item>
      <title>I Turned npm outdated into a CI Gate — Here’s How</title>
      <dc:creator>Sulthon Zainul Habib</dc:creator>
      <pubDate>Sun, 24 May 2026 16:51:20 +0000</pubDate>
      <link>https://dev.to/sulthonzh/i-turned-npm-outdated-into-a-ci-gate-heres-how-171f</link>
      <guid>https://dev.to/sulthonzh/i-turned-npm-outdated-into-a-ci-gate-heres-how-171f</guid>
      <description>&lt;p&gt;You run &lt;code&gt;npm outdated&lt;/code&gt; and see a list of stale packages. But your CI doesn't care. It passes anyway. Dependencies drift until something explodes in production. There's no built-in way to fail the build when versions drift too far.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;npm outdated&lt;/code&gt; lists outdated dependencies, but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No exit codes — CI cannot gate builds on the result&lt;/li&gt;
&lt;li&gt;No threshold configuration — you can't say "fail if &amp;gt;2 minors behind"&lt;/li&gt;
&lt;li&gt;No distinction between prod and dev dependencies in many workflows&lt;/li&gt;
&lt;li&gt;Manual updates become a fire drill instead of a controlled process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical scenario: Your team wants to stay current with security patches, but you can't update everything. You need a rule: "No production dependency more than 2 minor versions behind latest." &lt;code&gt;npm outdated&lt;/code&gt; can't enforce that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;I built &lt;code&gt;npm-outdated-check&lt;/code&gt; to turn &lt;code&gt;npm outdated&lt;/code&gt; into a first-class CI citizen with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic version thresholding (major/minor/patch drift limits)&lt;/li&gt;
&lt;li&gt;Meaningful exit codes (0 = pass, 1 = violation, 2 = config error, 3 = network error)&lt;/li&gt;
&lt;li&gt;Configurable via CLI flags or a &lt;code&gt;.npm-outdated-check.json&lt;/code&gt; config file&lt;/li&gt;
&lt;li&gt;Production/dev dependency filtering&lt;/li&gt;
&lt;li&gt;Multiple output formats (text, table, JSON)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The tool reads your &lt;code&gt;package.json&lt;/code&gt;, queries the npm registry for each dependency, calculates the semantic version difference, and flags anything that exceeds your thresholds.&lt;/p&gt;

&lt;p&gt;Key implementation details:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Registry fetching&lt;/strong&gt;: Hit the npm registry endpoint for each package and extract the &lt;code&gt;dist-tags.latest&lt;/code&gt; version&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semver diff&lt;/strong&gt;: Use &lt;code&gt;semver&lt;/code&gt; to parse &lt;code&gt;coerce(current)&lt;/code&gt; and &lt;code&gt;parse(latest)&lt;/code&gt;, then compute &lt;code&gt;major/minor/patch&lt;/code&gt; differences&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Violation logic&lt;/strong&gt;: A package violates if any diff exceeds its configured &lt;code&gt;maxMajor&lt;/code&gt;/&lt;code&gt;maxMinor&lt;/code&gt;/&lt;code&gt;maxPatch&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit codes&lt;/strong&gt;: CI reads the exit code and fails the build when violations exist&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sample threshold calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;majorDiff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;major&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;major&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minorDiff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minor&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;patchDiff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;patch&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isViolation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;majorDiff&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxMajor&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;minorDiff&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minorDiff&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;patchDiff&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxPatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Install globally or as a dev dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; npm-outdated-check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it in CI with sensible defaults (major=0, minor=2, patch=5):&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Add it to GitHub Actions:&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dependency Check&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&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;outdated-check&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;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;
      &lt;span class="pi"&gt;-&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;npm install&lt;/span&gt;
      &lt;span class="pi"&gt;-&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;npx npm-outdated-check --max-minor &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a dependency is 4 minor versions behind, CI fails and you get notified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Controlled updates&lt;/strong&gt;: Set thresholds to avoid surprise breaking changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security posture&lt;/strong&gt;: Enforce staying within N patch versions of latest&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team consistency&lt;/strong&gt;: Config rules checked automatically in CI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero config&lt;/strong&gt;: Works out of the box with smart defaults&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Roadmap items include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configurable notification channels (Slack, email)&lt;/li&gt;
&lt;li&gt;Automated PR generation for outdated packages&lt;/li&gt;
&lt;li&gt;Support for Yarn and pnpm lockfiles&lt;/li&gt;
&lt;li&gt;Monorepo workspace awareness&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/sulthonzh/npm-outdated-check" rel="noopener noreferrer"&gt;https://github.com/sulthonzh/npm-outdated-check&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Try it: &lt;code&gt;npm install -D npm-outdated-check&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>node</category>
      <category>ci</category>
    </item>
  </channel>
</rss>
