Skip to content

The Deska blog

Removing Unused Dependencies Without Breaking Prod

Learn a safe workflow for removing unused dependencies using automated tools and AI agents to keep your production environment stable and clean.

12 min read

Managing a growing codebase often leads to a cluttered dependency tree. Over time, libraries that were once essential become obsolete, yet they remain in your package.json or requirements file. The task of removing unused dependencies is critical for reducing bundle size, improving install times, and minimizing the security attack surface. However, simple removal can be risky. Modern software often relies on side effects or implicit imports that automated scripts might miss. This post explores a technical recipe to clean your environment while ensuring your production systems remain functional.

The Cost of Dependency Bloat

Every package added to a project brings a hidden cost. Even if a library is not actively imported in your source code, its presence in the lockfile affects the entire ecosystem of the project. Developers often hesitate to delete entries because they fear breaking a build pipeline or a runtime dynamic import.

The risks associated with keeping dead code include:

  • Increased vulnerability surface: Every package is a potential vector for security exploits.
  • Slower CI/CD cycles: Build runners must download, extract, and cache files that serve no purpose.
  • Version conflicts: Old packages might lock sub-dependencies to outdated versions, preventing other libraries from upgrading.
  • Bundle overhead: In frontend projects, tree-shaking is not always perfect. Some unused utility libraries might still find their way into the final assets.

Identifying Candidates for Removal

The first step in any cleanup is discovery. You cannot rely solely on a manual search for import statements, especially in large monorepos. Several tools specialize in static analysis to find orphan packages.

For JavaScript and TypeScript projects, depcheck is a standard choice. It analyzes the code to see how each dependency is used. It categorizes them into unused dependencies, missing dependencies, and unused devDependencies. While powerful, it is not infallible. It might flag a package as unused if it is only referenced in a configuration file or loaded dynamically at runtime.

In the Python ecosystem, vulture serves a similar purpose, finding unused code and suspicious imports. Regardless of the language, the output of these tools should be treated as a list of candidates rather than an absolute instruction. You must verify the findings before running a delete command.

A Safe Cleanup Recipe

To ensure you are removing unused dependencies without breaking prod, follow a structured verification process. This involves creating a feedback loop between static analysis and runtime testing.

  1. Run your static analysis tool and redirect the output to a text file for review.
  2. Cross-reference the list with your configuration files. Check if the "unused" package is a Peer Dependency or a plugin for your build tool, like Babel or Vite.
  3. Remove one package at a time. Mass deletions make it impossible to pinpoint which specific change caused a failure.
  4. Run your full test suite, including unit, integration, and end-to-end tests.
  5. Check your build artifacts. Ensure that the total size has decreased as expected and that the entry points are still functional.

Using AI Agents for Dependency Audits

Traditional static analysis ignores the context of why a package was added. AI coding agents, when given access to the full workspace, can provide a deeper layer of validation. They can read the documentation, look at commit history, and understand if a library is being used for a specific edge case that regex-based tools might miss.

Inside a flexible environment like the infinite canvas, you can run multiple agents side-by-side to verify the same set of packages. If you are using coding agents like Claude Code or OpenCode, you can instruct them to analyze a specific panel containing your package.json and then search the entire project for usage patterns.

This local-first approach ensures that your proprietary code remains on your machine while the agent does the heavy lifting. You can open a terminal panel to run the build while another panel displays the agent's reasoning. This transparency is vital. You should never let an agent delete files without your oversight. Using the terminals panel in your workspace allows you to see the exact output of every command the agent suggests.

Comparing Automated Approaches

ApproachTool ExamplesStrengthsWeaknesses
Static Analysisdepcheck, vultureFast, objective, easy to automate in CI.High false positive rate for dynamic code.
Manual Auditgrep, ripgrepHigh accuracy when performed by experts.Extremely time consuming for large projects.
Agentic AuditClaude Code, CodexHigh context awareness, understands intent.Requires API tokens, needs human supervision.
Runtime TrackingWebpack stats, ProfilersShows what was actually executed.Hard to set up for all possible code paths.

Moving Beyond Static Analysis with Deska

The challenge with traditional IDEs is that you often lose context when switching between the terminal, the code, and the results of a search. Deska addresses this by allowing you to organize your audit in a non-linear way. You can place your package.json in a central Monaco editor panel and surround it with terminal panels running different audit tools.

If you are unsure about a specific library, you can use Ask Deska to search your sessions or open a browser widget to check the library documentation. This allows you to verify if a package is required for a specific environment variable or a global polyfill. Because Deska is a free desktop app, you can keep these workspaces open for long-term maintenance tasks.

For developers who need to monitor long-running build tests after a cleanup, the mobile app provides a secure way to check the status of your terminal sessions. You do not need to stay at your desk while the CI suite validates your changes. You can see if the build failed and identify which package removal caused the break through the secure relay.

FAQ

How to find unused dependencies in node projects?

The most common method is using depcheck or npm-check. These tools scan your imports and compare them against your package.json. However, always double check packages used in build scripts or configuration files, as static analysis often misses these references.

Is it safe to delete devDependencies?

It is generally safer than deleting production dependencies, but it can still break your development workflow. Removing a linter or a test runner will not crash your production site, but it will cause your CI/CD pipeline to fail during the linting or testing phase.

Why does my bundle size stay the same after removing a package?

This usually happens if the package was already being successfully tree-shaken by your bundler. If the code was never imported in an entry point, the bundler likely ignored it anyway. Removing it still helps by keeping your node_modules clean and reducing security risks.

Start Cleaning Your Workspace

Maintaining a lean project is an ongoing process rather than a one-time task. By integrating agents and better visualization tools into your workflow, you can handle technical debt without the stress of breaking production. To begin organizing your next dependency audit on an infinite canvas, you can download the Deska desktop application for your operating system.