Detect Dead Exports JavaScript for Cleaner AI Code

Dan Greer · · 9 min read
Detect dead exports in JavaScript for cleaner code and improved AI project efficiency

If you work with AI-powered code tools, you already know how tough it is to detect dead exports JavaScript leaves behind: unused helpers, forgotten constants, and orphaned modules that confuse both automation and humans.

You’re not alone in facing duplicate logic, strange regressions, and opaque codebase bloat.

We’ve written a practical guide just for you, covering:

  • How to detect dead exports JavaScript projects accumulate, using static analysis and codebase graphs
  • Why dead exports disrupt AI-assisted workflows and inflate your attack surface
  • Step-by-step strategies for integrating export detection in modern, CI-driven, agent-augmented development

Why Dead Exports Hurt AI-Driven JavaScript Development

Dead exports are more than old code. They are clutter that holds your team back. If you build with Claude Code, Cursor, Windsurf, or GitHub Copilot, you know AI agents can’t spot the real structure of your repo. That means more time lost, higher risk, and tools that keep repeating the same mistakes.

What dead exports do to you:

  • Slow your onboarding and kill momentum. Every time you or an agent hits dead logic, it wastes time and causes second guessing.
  • Inflate surface area. Unused exports bloat dependency graphs, making code feel more complex than it is.
  • Increase the blast radius of agent mistakes. Orphaned helpers and abandoned files confuse AI, so agents either miss needed pieces or generate new ones, duplicating effort.
  • Create regression risk. Messy exports mean every refactor could break critical paths nobody can see.
  • Prevent agents from building reliably. Tree-shaking helps bundles but does nothing to clean your local source. You end up with more static-analysis noise and harder code search.
If you don’t track dead exports, every agent refactor makes your codebase riskier and your velocity drops.

Our experience at Pharaoh building end-to-end codebase knowledge graphs proves it: project-wide export detection transforms agent accuracy and, most of all, developer confidence.

Graphic illustrating how to detect dead exports in JavaScript for optimized AI-driven development

What Are Dead Exports in JavaScript?

Exports fuel your stack’s interoperability. But exports nobody calls or imports? That’s dead weight. These creep in from refactors, half-shipped features, or agent-generated stubs. We see three main forms:

  • Exported functions, constants, or classes that never leave their file. You might find export function unusedHelper() {} sitting in a utils module, unseen by the rest of your codebase.
  • Constants or enums only used in the file of origin. Like export const STALE = 'obsolete' hanging out in old config or helper files, serving nobody.
  • Types or interfaces (especially in TypeScript) that never appear in another file—or only matter in a file that already has local definitions.

Monorepos amplify this problem. Some exports look unreferenced in one package, but are only consumed by a test utility or a deploy script in another.

What creates dead exports?

  • Deprecated features where logic outlives UI.
  • Abandoned side projects and scaffolds copied from other repos.
  • AI agents producing helpers without full codebase context.
  • Barrel files (index.js/index.ts) that re-export everything, making real usage invisible.
Dead exports exist in every codebase, but AI-driven repos see them multiply fast if you don’t step in.
Detect dead exports in JavaScript with code analysis tools and strategies for cleaner modules.

How Can You Detect Dead Exports in JavaScript Projects?

Project-wide static analysis is the gold standard. Searching for imports or using ESLint helps only in the file you’re editing. That’s not enough for agent-driven teams. Static tools beat guesswork.

Static analysis tools for real detection

Let’s get specific:

  • Knip cuts to the chase. It checks your whole repo for unused exports, files, and dependencies. Monorepo ready. Flag unused files, auto-fix with a command, and focus review time only where it matters.
  • ts-prune (for TypeScript) inspects exported symbols throughout your project—great if your code is mostly typed and you want precision.
  • depcheck covers dead npm dependencies, not internal exports, so pair it with broader tools.

If you work with dynamic imports or barrel files, false positives creep in. These tools show you exactly what’s dead, but you still need human review for more complex patterns.

Detection methods and their strengths:

  • Knip: Best for monorepos, finds unused exports fast, diff review is simple, and you get concrete lists after every run.
  • ts-prune: Tight integration with the TypeScript compiler, perfect for typed codebases that avoid dynamic patterns.
  • ESLint: Locally helpful, but can’t build a dependency graph across your codebase or packages.
  • Manual searching: Slow, unreliable, and misses edge cases with barrel files or dynamic module loading.
Add static detection to your pre-merge CI and data-driven audits get easier. No more guesswork or risky, delayed cleanup.

How Tree-Shaking and ES Modules Impact Dead Export Detection

Modern bundlers sold us on tree-shaking. Export what you want, and let the tool sort it out. But that only cleans your production bundle. It does not touch your repo, your code search, or your agent’s intelligence.

Know what tree-shaking fixes—and what it can’t

Tree shaking checks the import/export graph, looks for unreachable code, and skips it in your JS bundle. That works well if your code follows ES module rules and avoids dynamic exports.

But here’s where things break:

  • CommonJS modules: Harder to shake. If you mutate exports at runtime, bundlers can’t prune them.
  • Dynamic imports: String-based or runtime logic makes export reachability invisible to static tools.
  • Side effects: A package with sideEffects: true in package.json disables aggressive tree-shaking.

Tree-shaking is essential, but it doesn’t keep your codebase clean. Dead exports stay in your repo, tripping up code search and AI reasoning.

Clean source, not just bundles. Agent-native development means every export in your codebase has a real consumer.

Common Causes of Dead Exports in Real-World Projects

If your repo grows fast, especially with AI agents in the loop, you get dead exports from several sources. These aren’t random—they happen in patterns.

Key sources of dead exports:

  • Feature removals that only cut UI, not backend helpers.
  • Barrel files that re-export every module. Real usage blurs, static tools cry uncle, and dead exports merge in hidden.
  • Migration and copy-paste: Copy in a module “just in case” but forget to audit real imports after.
  • Agent-driven development: AI outputs helpers and exports without checking if they’re used downstream or if similar logic already exists.
  • Defensive coding: Exporting for potential, “future” use, that never materializes.

Production code, test utilities, and config files all contribute. If you generated 1,000+ lines with agents, expect at least 10% to go unused without project-wide detection.

The more code you copy or auto-generate, the faster this technical debt piles up.

Best Practices to Prevent and Manage Dead Exports

Don’t wait for technical debt to bury your team. Proactivity prevents pain. We’ve found that a discipline-focused approach keeps projects agent-ready and export lists tight.

Direct steps to keep your codebase export-lean

  • Ban or lint against barrel files at the entrypoint. Prefer explicit, granular exports to support static analysis and kill dead logic before it arrives.
  • Use granular entrypoints, not catch-all barrels. Subpath exports in package.json boost tree-shaking and traceability.
  • Integrate automated detection as CI checks. Tools like Knip or ts-prune catch dead exports early—fail PRs to stop the rot before it infects main.
  • Audit after every major refactor, AI sprint, or feature removal, not just yearly. Fast feedback cycles mean less pain if you catch exports early.
  • For agent-native teams, wire AI PRs to knowledge graph queries or blast radius tools for deterministic export reachability before merge.

Small PRs win. Remove extra exports bit by bit. Assign ownership to exported APIs. Document public vs internal explicitly. Use config files and ignore lists for dynamic consumers and keep your repo future-proofed for both human and agent development.

Every clean export is one less chance for your AI tools to misfire, duplicate effort, or sink your development velocity.

How Is AI Changing Dead Export Detection in JavaScript?

AI agents should help you move fast, not keep you second-guessing if you’re accidentally duplicating old logic. The truth: most agent-powered tools scan files, not the whole codebase graph. That limits how smart your automation can be.

Dead exports multiply unless your workflows close the loop. Without a structural map, every agent suggestion is a guess at best.

The new advantage: codebase knowledge graphs

When your codebase becomes a graph, AI agents and developers can:

  • Run live reachability queries. “Does anything import this export?” becomes a fact, not a hope.
  • See architectural blast radius before merge. Know the real impact of every removal.
  • Stop exporting ghosts. No more never-used helpers after an AI sprint.

Pharaoh takes this to the next level. By turning your repo into a Neo4j knowledge graph via MCP and parsing with Tree-sitter, we offer structured, queryable insight for both people and AI agents. After initial indexing, reachability and dependency checks are instant—no guesswork, no token cost, and always up-to-date.

The right graph transforms agents from code generators into smart maintainers. That’s less risk and more value for every push and pull request.

A Real-Life Example: Cleaning up a Large Monorepo

You’re working in a repo packed with forgotten helpers, old components, and mystery utilities. Do you trust an ordinary agent sweep or hunt them down one by one? Here’s how disciplined teams get clarity fast.

Breaking down the cleanup process

  • Scan with project-wide detectors like Knip. See hard data: unused files, exports, dependencies.
  • Review dynamic imports, test-only utilities, and config scripts. Flag false positives early.
  • Combine static results with entry point tracing or a Pharaoh-powered knowledge graph. Confirm that every recommended removal is safe.
  • Ship in small, testable PRs. Each pass gets cleaner with fewer surprises.

Teams using this playbook report: fewer regressions, faster test suites, and smoother agent PRs. When there’s nothing dead or hidden, AI-generated fixes work the first time, not after three rounds of manual patching.

When you remove code nobody needs, you unlock agility that is visible every single day.

Step-by-Step: Setting up Dead Export Detection in Your JavaScript Repo

Ready to protect your velocity and cut out the cruft? Focus on real integration, fast feedback, and knowledge-driven automation.

Rapid-action setup checklist

  • Run Knip or ts-prune at your workspace root. Tune configs for your entrypoints and ignore lists.
  • Add detection as a GitHub Action or in your CI pipeline. Fail PRs with new or returned dead exports.
  • Audit findings. Separate true dead exports from test hook false positives.
  • Connect your repo to Pharaoh for codebase graphing. Gain instant reachability queries and no-token cost blast radius checks for every PR.

Documents, config files, and pull request policies matter. The best teams back every removal with certainty using project-wide tools, not just intuition.

Lay the groundwork once—clean code and agent-smart AI checks stick with you for the long run.

Frequently Asked Questions About Dead Exports in JavaScript

You want to move fast, but you don’t want to break real users or published APIs. The right export discipline protects both.

Most common questions and what works:

  • Should I remove every detected dead export? Not blindly. Check for dynamic usage, runtime imports, and external consumers before you delete.
  • What if static tools generate false positives? Pair analysis with runtime tracing, solid configs, and knowledge-graph queries from Pharaoh for an always-accurate answer.
  • How do I protect package libraries used elsewhere? Treat exports as contracts, evolve APIs using subpath exports, and prefer warnings before deletions.
  • How can teams automate audits? Use pre-merge CI checks, agent policy gating, and regular project-wide scans for ongoing discipline.
  • Why codebase export analysis over local lints? Architectural intelligence beats file-by-file guesswork, especially for agent-native stacks.
Small teams using structured graphs and automated checks cut tech debt before it hits main, not after it ruins a release.

How Codebase Graphs Transform Dead Export Detection and AI Productivity

When you shift from intuition to structured maps, agents stop guessing and start building with confidence. Every export is real, used, and accounted for.

Pharaoh gives you this clarity: a queryable, managed graph powered by Neo4j and Tree-sitter that turns dead export detection into a fast, reliable step. Look up reachability, see module relationships, and approve PRs you can trust.

Once you’ve indexed your repo, you no longer spend days chasing bug reports caused by orphaned helpers. Your AI agents make fewer mistakes and your velocity jumps with every clean audit.

You win when your codebase becomes a living map—not a haunted house of past exports.

Conclusion: Make Every Export Count for Agent-Native Development

Every dead export drains your time, raises agent error risk, and slows real velocity. Use project-wide detection, discipline, and codebase graphs to guarantee clarity. With Pharaoh in your stack, you’re no longer guessing. You’re building with certainty, shipping faster, and empowering agents to follow the real structure—not just the surface.

Cut the clutter. Clean up your exports. Build with the confidence only a codebase graph can deliver. Start mapping your repo at pharaoh.so and see your AI agents finally catch up to your ambition.

← Back to blog