Safeguard
Developer Tools•

Do devDependencies end up in your production JavaScript bundle?

The dependencies or devDependencies label does not decide what a bundler ships. Imports do. Learn how tree shaking works, where it stops, and how to check.

Safeguard Security Team
3 min read

Not by label. A bundler includes code your application imports, whether the package is listed under dependencies or devDependencies. A devDependency nothing imports stays out of the bundle. Tree shaking trims unused exports, but it does not remove everything, so check what your build actually ships.

Two different questions

People mix up two things. The first is what gets installed on a server or in a container image. The second is what a bundler packs into files sent to browsers.

For installs, the npm install documentation says omitted dev dependencies are still resolved and recorded in the lockfile, but they are not physically installed on disk. That is the production flag at work, and it matters for server images.

For bundles, the webpack guide explains that tree shaking works from the static import and export structure of ES modules. The label in package.json is not part of that logic. If your source imports a package, it is bundled. If nothing imports it, it is not.

Where tree shaking stops

The webpack guide is clear that tree shaking does not remove all unused code. Its analysis is conservative with dynamic JavaScript, and modules that might have side effects are kept. Code transpiled to CommonJS is not tree shaken. The sideEffects field in package.json tells the bundler which files are safe to skip when their exports are unused, but setting it wrongly can drop code you needed, such as CSS imported only for styles.

So a vulnerable function inside a package you import may still ship even if you call only one other function.

How to check what shipped

  1. Build for production with the same settings as your release.
  2. Run your bundler's analysis or stats output to list included modules.
  3. Compare the module list to your lockfile. Anything in the bundle is in scope for vulnerability triage.
  4. Move build-only tools such as test runners and linters out of your production install with the omit flag for dev dependencies.
  5. Keep the list as an SBOM so it is easy to answer "were we exposed?" later.
QuestionWhere to look
What runs on my server?Installed production dependencies
What do browsers download?Bundle module list
What might be vulnerable?Lockfile, narrowed by what is imported or reachable

Try it yourself

Click through it at your own pace, or open it full screen.

Compare the full finding list with the reachable subset. Shipped code and reachable code are not the same thing, and both matter.

Quick check

If a package is in devDependencies, can it still reach users?

Yes, if your application code imports it and your bundler includes it. The category does not control bundling.

Does tree shaking remove all unused code?

No. The webpack guide says it is conservative and keeps modules it cannot prove are free of side effects.

Safeguard pairs dependency scanning with reachability analysis, so you can focus on vulnerable code your application can actually call. Try the free scan at gold.safeguard.sh/scan. Related: does npm audit flag a dev dependency, and do I need to fix it.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.