<?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: Bart Waardenburg</title>
    <description>The latest articles on DEV Community by Bart Waardenburg (@bartwaardenburg).</description>
    <link>https://dev.to/bartwaardenburg</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%2F338786%2Fe4b6fde5-58ba-41ce-8c51-de5495fa3764.jpeg</url>
      <title>DEV Community: Bart Waardenburg</title>
      <link>https://dev.to/bartwaardenburg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bartwaardenburg"/>
    <language>en</language>
    <item>
      <title>I built fallow: Rust-native codebase intelligence for TypeScript and JavaScript</title>
      <dc:creator>Bart Waardenburg</dc:creator>
      <pubDate>Mon, 23 Mar 2026 15:27:34 +0000</pubDate>
      <link>https://dev.to/bartwaardenburg/i-built-a-rust-based-codebase-analyzer-that-finds-dead-code-in-jsts-projects-in-milliseconds-180i</link>
      <guid>https://dev.to/bartwaardenburg/i-built-a-rust-based-codebase-analyzer-that-finds-dead-code-in-jsts-projects-in-milliseconds-180i</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; &lt;a href="https://github.com/fallow-rs/fallow" rel="noopener noreferrer"&gt;fallow&lt;/a&gt; is Rust-native codebase intelligence for TypeScript and JavaScript. The free static layer finds unused code (files, exports, types, enum and class members, dependencies), code duplication, circular dependencies, complexity hotspots, and architecture boundary violations across your module graph. Zero config, 95 framework plugins auto-detected, sub-second on most projects. An optional paid runtime layer (Fallow Runtime) adds production execution evidence on top. &lt;code&gt;npx fallow&lt;/code&gt; to try it now.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem that kept bugging me
&lt;/h2&gt;

&lt;p&gt;Every codebase I've worked on has structural drift. Exports that nothing imports. Dependencies in &lt;code&gt;package.json&lt;/code&gt; that no file uses. Files that were "temporarily" left in after a refactor six months ago. Entire utility modules where 3 out of 12 functions are actually called. Modules that import each other in cycles. Functions that have quietly become complexity hotspots. Boundaries that were supposed to separate features but have leaked across the codebase.&lt;/p&gt;

&lt;p&gt;That drift isn't free. It bloats your bundle, slows your builds, and confuses anyone new to the project because they can't tell what's actually used and what's left over from two refactors ago. The cycles make builds fragile. The complexity hotspots accumulate in the busiest paths. And the longer nobody touches any of it, the scarier it gets to change.&lt;/p&gt;

&lt;p&gt;This was annoying but manageable when humans wrote all the code. Now AI coding agents generate code at a pace where nobody can keep track of what's still needed. They create new files, refactor existing ones, but never go back to clean up what they left behind. They can't, really. Determining whether an export is unused, whether a module is in a cycle, or whether a function has tipped over a complexity threshold requires building a complete model of the codebase across every file. That is a graph problem, not a "read the file and figure it out" problem.&lt;/p&gt;

&lt;p&gt;Existing tools work, but they were slow enough that I'd only run them occasionally. So I built fallow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Fallow builds the full import/export graph of your project and reports across five analysis areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unused code:&lt;/strong&gt; files, exports, types, enum members, class members, dependencies, devDependencies, unresolved imports, unlisted dependencies, duplicate exports, unused pnpm catalog entries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code duplication:&lt;/strong&gt; suffix-array clone detection in four modes (strict, mild, weak, semantic), with clone families that suggest whether to extract a function or a module&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circular dependencies:&lt;/strong&gt; cycle detection across the full module graph, with no depth limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity hotspots:&lt;/strong&gt; cyclomatic and cognitive complexity per function, refactoring targets, and per-file complexity-density rankings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture boundaries:&lt;/strong&gt; zone definitions with &lt;code&gt;allow&lt;/code&gt; lists, presets (Layered, Hexagonal, FeatureSliced, Bulletproof), &lt;code&gt;autoDiscover&lt;/code&gt; parent zones, and a per-rule &lt;code&gt;allowTypeOnly&lt;/code&gt; escape hatch for type-only imports across zones&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what it looks like:&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="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;fallow
&lt;span class="go"&gt;
● Unused files (16)
  src/server/jobs/worker.ts
  src/server/jobs/cron.ts
  src/features/savings/hooks/usePotGroups.ts
  ... and 13 more

● Unused exports (20)
  src/components/Card/index.ts
    :1 CardFooter
  src/providers/trpc-provider/index.tsx
    :12 TRPCProvider

● Unused dependencies (1)
  @trpc/react-query

● Duplicate exports (50)
  ... across 23 files

● Clone groups (1,184)
  ... 19.4% duplication across 398 files

● Complexity hotspots (12)
  ... cyclomatic 28 in src/features/forecasting/server/procedures/analytics.ts

Found 401 issues in 0.16s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line is the part I'm most proud of. 0.16 seconds for 401 issues across a real-world codebase.&lt;/p&gt;

&lt;p&gt;An optional paid runtime layer (Fallow Runtime) ingests production V8 coverage and joins it back to the static graph so the same report can flag hot-path changes, surface cold paths with deletion confidence, and retire stale flags with proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Rust
&lt;/h2&gt;

&lt;p&gt;I didn't pick Rust to be trendy. The bottleneck in cross-file analysis is parsing every file in the project to build the module graph. Fallow uses the &lt;a href="https://oxc.rs/" rel="noopener noreferrer"&gt;Oxc parser&lt;/a&gt; natively in Rust (not through NAPI bindings) and &lt;a href="https://github.com/rayon-rs/rayon" rel="noopener noreferrer"&gt;rayon&lt;/a&gt; for parallel file processing across all cores. If you're already looking at &lt;a href="https://oxc.rs/docs/guide/usage/linter" rel="noopener noreferrer"&gt;oxlint&lt;/a&gt; or &lt;a href="https://oxc.rs/docs/guide/usage/formatter" rel="noopener noreferrer"&gt;oxfmt&lt;/a&gt;, fallow is the same family. Linters check files. TypeScript checks types. Fallow checks the codebase.&lt;/p&gt;

&lt;p&gt;Here is how that plays out on real projects:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;Files&lt;/th&gt;
&lt;th&gt;fallow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;zod&lt;/td&gt;
&lt;td&gt;174&lt;/td&gt;
&lt;td&gt;19ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preact&lt;/td&gt;
&lt;td&gt;244&lt;/td&gt;
&lt;td&gt;20ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fastify&lt;/td&gt;
&lt;td&gt;286&lt;/td&gt;
&lt;td&gt;24ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vue/core&lt;/td&gt;
&lt;td&gt;522&lt;/td&gt;
&lt;td&gt;63ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TanStack/query&lt;/td&gt;
&lt;td&gt;901&lt;/td&gt;
&lt;td&gt;148ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;svelte&lt;/td&gt;
&lt;td&gt;3,337&lt;/td&gt;
&lt;td&gt;325ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;next.js&lt;/td&gt;
&lt;td&gt;20,416&lt;/td&gt;
&lt;td&gt;1.48s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sub-second on every project up to 3,000+ files, and 1.5 seconds on a 20,000-file Next.js monorepo. Memory usage stays in the low hundreds of MB even on the big ones, which matters in CI. The dedicated &lt;a href="https://docs.fallow.tools/migration/comparison" rel="noopener noreferrer"&gt;comparison page&lt;/a&gt; has the full matrix against existing Node-based tooling if you want the side-by-side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Duplication detection built in
&lt;/h2&gt;

&lt;p&gt;Most projects I've worked on also have a copy-paste problem. fallow has a &lt;code&gt;dupes&lt;/code&gt; command that finds duplicated code blocks using a suffix array algorithm (no quadratic pairwise comparison):&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="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;fallow dupes
&lt;span class="go"&gt;
Clone group 1 (42 lines, 3 instances)
├─ src/features/forecasting/server/procedures/analytics.ts:141-181
├─ src/features/forecasting/server/procedures/cashflow.ts:153-194
└─ src/features/forecasting/server/procedures/income.ts:590-631

Duplication: 19.4% (27,255 duplicated lines across 398 files)
Found 1,184 clone groups, 2,959 instances (0.23s)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four detection modes: &lt;code&gt;strict&lt;/code&gt; (exact), &lt;code&gt;mild&lt;/code&gt; (default), &lt;code&gt;weak&lt;/code&gt; (different string literals), and &lt;code&gt;semantic&lt;/code&gt; (catches renamed variables too). Clone families group related duplicates and suggest whether to extract a function or a module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexity, hotspots, and architecture boundaries
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;fallow health&lt;/code&gt; computes cyclomatic and cognitive complexity per function, surfaces complexity hotspots, ranks refactoring targets, and reports vital signs (duplicated lines, files scored, total deps). &lt;code&gt;fallow list --boundaries&lt;/code&gt; and the boundary rules in &lt;code&gt;.fallowrc.json&lt;/code&gt; enforce architecture zones so a feature module can't import from a sibling feature unless an &lt;code&gt;allow&lt;/code&gt; rule says so. Presets cover Layered, Hexagonal, Feature-Sliced, and Bulletproof out of the box; &lt;code&gt;autoDiscover&lt;/code&gt; expands a parent zone into one child per immediate subdirectory automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero config, 95 plugins
&lt;/h2&gt;

&lt;p&gt;Fallow reads your &lt;code&gt;package.json&lt;/code&gt; and auto-detects your framework stack. Next.js, Vite, Vitest, Playwright, Storybook, ESLint, Tailwind, Prisma, Drizzle, Turborepo, Nx, Angular, NestJS, AdonisJS, Expo Router, and more. 95 plugins total, with deep config-file parsing for the ones that matter (reading &lt;code&gt;next.config.js&lt;/code&gt;, &lt;code&gt;vite.config.ts&lt;/code&gt;, &lt;code&gt;astro.config.mjs&lt;/code&gt;, etc. to understand entry points and aliases).&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;.fallowrc.json&lt;/code&gt; required unless you want to customize. Just run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-fix
&lt;/h2&gt;

&lt;p&gt;Fallow can remove unused exports, unused dependencies, and unused enum members automatically:&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;# Preview what would change&lt;/span&gt;
fallow fix &lt;span class="nt"&gt;--dry-run&lt;/span&gt;

&lt;span class="c"&gt;# Apply fixes&lt;/span&gt;
fallow fix

&lt;span class="c"&gt;# Non-interactive for CI/agents&lt;/span&gt;
fallow fix &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It only touches things it's confident about. Unused files aren't auto-deleted because that's a bigger decision you should make yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why fallow over what you have today
&lt;/h2&gt;

&lt;p&gt;A few reasons fallow might be a better fit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed is a pain point (especially in CI or watch mode)&lt;/li&gt;
&lt;li&gt;You want unused code, duplication, circular deps, complexity hotspots, and boundary checks in one tool instead of four&lt;/li&gt;
&lt;li&gt;You need SARIF output for GitHub Code Scanning&lt;/li&gt;
&lt;li&gt;You want &lt;code&gt;--diff-file&lt;/code&gt; to scope every finding to lines changed in a PR&lt;/li&gt;
&lt;li&gt;You want inline suppression comments (&lt;code&gt;// fallow-ignore-next-line&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;You want baseline comparison for incremental adoption in existing projects&lt;/li&gt;
&lt;li&gt;You use AI coding agents and want structured JSON output or MCP integration&lt;/li&gt;
&lt;li&gt;You plan to eventually layer in production runtime evidence (Fallow Runtime)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;fallow migrate&lt;/code&gt; converts existing tool configs into a fallow config automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI agent integration
&lt;/h2&gt;

&lt;p&gt;This is the use case I care about most. Agents generate code but have no way to know what's unused, duplicated, or structurally drifted across the full project. Fallow gives them that:&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;# Agent checks its own work after generating code&lt;/span&gt;
fallow audit &lt;span class="nt"&gt;--diff-file&lt;/span&gt; pr.diff &lt;span class="nt"&gt;--format&lt;/span&gt; json

&lt;span class="c"&gt;# Agent auto-fixes what it can&lt;/span&gt;
fallow fix &lt;span class="nt"&gt;--yes&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also an MCP server (&lt;code&gt;fallow-mcp&lt;/code&gt;) that exposes typed tools (&lt;code&gt;analyze&lt;/code&gt;, &lt;code&gt;check_changed&lt;/code&gt;, &lt;code&gt;find_dupes&lt;/code&gt;, &lt;code&gt;check_health&lt;/code&gt;, &lt;code&gt;fix_preview&lt;/code&gt;, &lt;code&gt;fix_apply&lt;/code&gt;, &lt;code&gt;project_info&lt;/code&gt;) so agents can call them directly. Works with Claude Code, Cursor, Codex, Windsurf, Gemini CLI, and any MCP-compatible agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI integration
&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 Actions&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;fallow-rs/fallow@v2&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;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sarif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SARIF output uploads to GitHub Code Scanning for inline PR annotations. &lt;code&gt;--diff-file&lt;/code&gt; scopes every finding to lines inside an added hunk. &lt;code&gt;--save-baseline&lt;/code&gt; and &lt;code&gt;--baseline&lt;/code&gt; let you adopt incrementally without fixing every existing issue first. A GitLab CI template is bundled too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;No install, no config, no signup. Takes about a second on most projects, and you get unused code, duplication, circular deps, complexity hotspots, and boundary violations in one pass.&lt;/p&gt;

&lt;p&gt;If you want a single category:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx fallow dead-code     &lt;span class="c"&gt;# unused-code rules only&lt;/span&gt;
npx fallow dupes         &lt;span class="c"&gt;# duplication only&lt;/span&gt;
npx fallow health        &lt;span class="c"&gt;# complexity + hotspots + refactoring targets&lt;/span&gt;
npx fallow list &lt;span class="nt"&gt;--boundaries&lt;/span&gt;  &lt;span class="c"&gt;# architecture zones&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/fallow-rs/fallow" rel="noopener noreferrer"&gt;fallow-rs/fallow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://docs.fallow.tools" rel="noopener noreferrer"&gt;docs.fallow.tools&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;VS Code: &lt;a href="https://marketplace.visualstudio.com/items?itemName=fallow-rs.fallow-vscode" rel="noopener noreferrer"&gt;fallow-rs.fallow-vscode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MIT licensed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love feedback. If fallow finds something useful (or misses something it shouldn't), open an issue or drop a comment here.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>node</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
