← All Articles 📦 Dependency Vulnerabilities Medium By Nishant Kumar Verma Updated

Excessive Dependencies in AI-Generated Apps: Bundle Bloat Problem

AI tools install 60+ packages for a simple app. Learn how dependency bloat increases attack surface, slows your app, and how to trim it.

DEP-001 DEP-004 DEP-006 DEP-007

Quick Answer

AI tools like Bolt, Lovable, and Cursor install dozens of npm packages to solve simple problems - a basic CRUD app can arrive with 50 or more dependencies. Each package adds attack surface (more code that can contain vulnerabilities), bloats your JavaScript bundle, and slows your users down. The fix is to audit your dependencies regularly, remove unused packages, and use lightweight alternatives.

How Many Packages Is Too Many?

When you ask Bolt to "build a task management app," it doesn't just install React. It installs React, a UI component library, a form library, a validation library, a date formatting library, an icon library, a state management library, and several others - often before you've even asked for those features. The resulting package.json can list 50 or more direct dependencies for an app that's essentially a to-do list. Projects built on Lovable's starter template share the same 49 production dependencies (example), most of them UI components that ship with the template.

Every direct dependency brings its own transitive dependencies, so the tree you ship is much larger than your package.json suggests. For AI-generated apps, that number is routinely higher because AI tools default to well-known packages rather than asking whether they're needed.

Every dependency adds upkeep: updates, security patches and version conflicts to resolve. Every dependency you don't need is time and risk you don't need.

This isn't just a performance concern. In the npm ecosystem, each package is a potential attack vector. The 2021 ua-parser-js supply chain attack, the node-ipc sabotage, and the event-stream compromise all targeted widely-used npm packages. A smaller dependency tree is a smaller attack surface.

What AI-Generated package.json Files Look Like

Here's a realistic example of what a Bolt or Lovable app's package.json looks like after scaffolding a basic SaaS dashboard:

// ❌ BAD - overlapping libraries for a simple dashboard (excerpt)
{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "next": "^14.0.0",
    "@mui/material": "^5.15.0",
    "@mui/icons-material": "^5.15.0",
    "@emotion/react": "^11.11.0",
    "@emotion/styled": "^11.11.0",
    "react-hook-form": "^7.49.0",
    "zod": "^3.22.0",
    "@hookform/resolvers": "^3.3.0",
    "date-fns": "^3.0.0",
    "moment": "^2.30.0",
    "lodash": "^4.17.21",
    "axios": "^1.6.0",
    "react-query": "^3.39.0",
    "@tanstack/react-query": "^5.0.0",
    "zustand": "^4.4.0",
    "jotai": "^2.6.0",
    "framer-motion": "^10.16.0",
    "react-spring": "^9.7.0",
    "recharts": "^2.10.0",
    "chart.js": "^4.4.0",
    "react-chartjs-2": "^5.2.0"
  }
}

Notice the redundancy: both moment and date-fns for date handling; both zustand and jotai for state; both react-query v3 and @tanstack/react-query v5 (the same library, two versions); multiple charting libraries. AI tools don't audit what they've already installed.

The Bundle Size Consequence

Every production dependency ships code to your users. Heavy packages have a real cost:

Package Minified + Gzipped Lightweight Alternative Alternative Size
moment.js ~75 KB date-fns (tree-shakeable) Under 1 KB for most functions (format is ~5 KB)
lodash 25 KB (full build) lodash-es (tree-shakeable) ~1-5 KB per function
axios ~11 KB native fetch 0 KB
@mui/material ~140 KB (full) shadcn/ui (copy-paste) Only what you use
framer-motion + react-spring ~62 KB combined CSS transitions 0 KB

Sizes from Bundlephobia for the versions in the example above (moment 2.30, lodash 4.17, axios 1.6, MUI 5.15, framer-motion 10.16, react-spring 9.7), minified and gzipped.

Every kilobyte of JavaScript has to be downloaded, parsed and executed, and that cost is highest on mid-range phones. An AI-generated app carrying 500 KB of unnecessary JavaScript makes every visitor download, parse and run all of it before a single line of your own code runs.

How to Audit Your Dependencies

A proper dependency audit covers three things: what's installed, what's actually used, and what's vulnerable.

# Step 1: List your direct dependencies
npm list --depth=0

# Step 2: Find unused dependencies (depcheck)
npx depcheck

# Step 3: Analyze bundle size impact
npx bundle-phobia-cli lodash moment axios

# Step 4: Check for known vulnerabilities
npm audit

# Step 5: Find duplicate packages in the installed tree
npm find-dupes

The depcheck tool scans your code and flags packages listed in package.json that aren't imported anywhere. This is the fastest way to find dead weight, and AI-generated projects often have some on the first run.

The Right Way to Manage Dependencies

// ✅ GOOD - Lean, intentional dependencies
{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "next": "^14.0.0",
    "react-hook-form": "^7.49.0",
    "zod": "^3.22.0",
    "@hookform/resolvers": "^3.3.0",
    "@tanstack/react-query": "^5.0.0",
    "date-fns": "^3.0.0"
  },
  "devDependencies": {
    "typescript": "^5.3.0",
    "@types/react": "^18.2.0",
    "eslint": "^8.55.0",
    "prettier": "^3.1.0"
  }
}

This setup covers form handling, validation, server state, and dates - everything a typical SaaS dashboard needs. No animation libraries until you specifically need them. No icon libraries until you pick one. No state management library until React's built-in state proves insufficient.

How to Fix Dependency Bloat in Your AI-Generated App

  1. Run depcheck first: Uninstall everything that isn't imported. Start there - it's the easiest win.
  2. Deduplicate: If you have both moment and date-fns, pick one and migrate. If you have two state management libraries, choose one.
  3. Check native alternatives: The browser's native fetch, Intl.DateTimeFormat, and CSS animations cover a lot of ground without any npm package.
  4. Use bundle analysis: Add @next/bundle-analyzer to your Next.js config or add the rollup-plugin-visualizer plugin to your Vite config to see exactly what's in your bundle.
  5. Automate scanning: Tools like VibeDoctor's Vibe Check look up every package in your package.json on the npm registry and flag ones that do not exist, are deprecated or look like typosquats, and run Trivy to list known CVEs in your lockfile. Free to sign up.

FAQ

How many npm packages is normal for a Next.js app?

There is no fixed number. Projects built on Lovable's starter template already list 49 production dependencies, most of them UI components. What matters is that every package is used, maintained, and not doing the same job as another one.

Does tree shaking fix bundle bloat from large packages?

Partially. Tree shaking removes unused exports at build time, but only if the package uses ES module syntax. CommonJS packages (like lodash) don't tree-shake by default. Even with tree shaking, having a dependency means it's in your supply chain and vulnerability surface.

What's the difference between DEP-001, DEP-004, DEP-006, and DEP-007?

DEP-001 is about an excessive count of production dependencies. DEP-004 is about duplicate libraries that solve the same problem (e.g., two date libraries, two HTTP clients). DEP-006 is about production dependencies that are never imported. DEP-007 is about importing a whole heavy library (all of lodash, moment or rxjs) instead of the part you use.

Will removing unused packages break my app?

If depcheck says a package is unused and you don't see any direct imports, removing it is safe. Always test after removing. Some packages are registered as plugins at runtime (e.g., via next.config.js) which static analysis can miss. depcheck recognizes some of these, but its README warns of false alerts, so check each one before you remove it.

Why do AI tools install so many packages?

AI tools are trained on code from the internet, which tends to use popular, well-documented packages. They optimize for working code, not minimal code. They also lack context about what you've already installed, so they add packages defensively rather than checking if something equivalent exists.

Diagnose your codebase - free

VibeDoctor checks for DEP-001, DEP-004, DEP-006, DEP-007 and 148 other issues across 21 diagnostic areas - security, performance, code quality, and more.

SCAN MY APP →