Dependency bloat in React Native: why AI tools can't solve your upgrade pain
AI tools make it trivial to scaffold a React Native app in minutes. But ask anyone who has tried to ship that code six months later and you hear the same story: the real wall is dependency rot, not missing features. The model writes the screens, yet nobody owns the upgrades, the version pins, or the decision log behind each package.
That gap is why the recent push for dependency intelligence matters. Package Intelligence for React Native and Expo teams promises a single dashboard: upload your package.json and get a report covering package health, compatibility, upgrade opportunities, bundle impact, risk detection, and migration recommendations. It is built specifically for React Native and Expo projects, which is exactly where AI-scaffolded apps hurt most.
The dashboard is useful. It is not a cure. This post explains why AI scaffolding hides the real risk, where version drift actually bites, and what owning your stack looks like in practice.
What dependency intelligence actually covers
The core questions behind the tooling are the right ones. As the Package Intelligence announcement frames it, growing React Native and Expo projects keep asking: is this package still maintained, does it support Expo, is it compatible with the New Architecture, are better alternatives available, how much does it cost in bundle size, and which packages are introducing technical debt. Answering that normally means jumping between npm, GitHub, changelogs, and community threads.
A dashboard that centralizes those answers saves real time. Upload the manifest, get health plus compatibility plus upgrade guidance in one place. For teams inheriting an AI-generated codebase with fifty unknown packages, that first report is genuinely clarifying.
But notice the assumption baked in: that there is a strategy to monitor. Most AI-generated projects do not have one. There is no rationale for why each package was chosen, no pinning policy, no deprecation plan. A dashboard can surface the rot. It cannot retroactively create the decisions. If your retrofit starts here, start with the report, then fix the process that made the report scary.
For the shipping discipline around that process, see our ship AI MVP to production checklist — dependency hygiene is one gate among several, and it works best alongside the others.
Why AI scaffolding hides version decisions
A model optimizes for working code right now. It picks packages that plausibly satisfy the prompt, often with caret ranges that float forward silently. It does not record why it chose one date library over another, whether the UUID helper is maintained, or which navigation major the template was written against.
Consider the following illustrative example, representative of AI-generated Expo manifests rather than a real audit of any specific project:
{
"dependencies": {
"@react-navigation/native": "^6.1.6",
"expo": "~50.0.0",
"react-native-reanimated": "^3.7.0",
"moment": "^2.29.4",
"random-uuid": "^1.0.0"
}
}Every line raises a question the manifest cannot answer. Why moment instead of a maintained lightweight alternative. Whether random-uuid is maintained at all. Which reanimated minor the native build was actually tested against. The official Expo documentation takes the opposite approach: one JavaScript and TypeScript project with pinned, tested native modules and official templates where versions move together. AI output floats; official templates pin.
The fix is boring and human: every non-obvious dependency gets a one-line rationale, versions get pinned in the lockfile, and anything without a reason gets removed. Dashboards help you find the suspects. Only you can convict them.
Keep that rationale where future you will actually read it. Our guide to an agent-readable repository structure shows where decision logs live so both humans and coding agents respect them.
One codebase. iOS, Android, and web.
The Fitness Kit ships with auth, a database, and a backend already connected — no setup. Live demo at fitness-preview.otf-kit.dev.
Version drift breaks faster than app code
Upgrading dependencies is the silent killer of React Native projects. An Expo SDK major moves dozens of native modules at once, peer ranges shift, and UI regressions appear in screens nobody touched. AI-generated code does not know which APIs are stable or which libraries are dead, so the upgrade lands as a pile of warnings and a lost weekend.
The failure modes are familiar to anyone who has done an SDK bump. A native module like reanimated needs a rebuild after the upgrade, and Metro serves a cryptic invariant violation until it gets one. A navigation major bump stalls on peer mismatches because the stack navigator still expects the older core. None of this is the model's fault exactly — it scaffolded against whatever was current at generation time — but the model is also absent when the bill arrives.
Illustrative error surface teams hit during these bumps:
ERROR: Invariant Violation: "main" has not been registered.
- Metro running from the wrong folder, or
- react-native-reanimated needs a rebuild after the SDK bumpnpm ERR! Could not resolve dependency:
npm ERR! peer @react-navigation/native@"^5.0.0"
from @react-navigation/stack@5.14.9Treat upgrades as scheduled maintenance, not emergencies. Read the SDK release notes before bumping, upgrade in a branch, rebuild native artifacts cleanly, and run the full smoke path on a real device. Monthly npm outdated plus npm audit runs catch drift while it is still cheap. The teams that dread upgrades are almost always the teams that skipped the monthly pass.
Transitive dependencies are the silent majority
Direct dependencies are the packages you chose. Transitive dependencies are everything they dragged along — routinely the large majority of installed packages in a React Native project. AI scaffolding never surfaces them, and many dashboards only emphasize the top level.
Run the tree and look at the depth:
npm ls --depth=2
npm audit
npm outdatedA minor bump three levels down can break a build or introduce a vulnerability in a parser you have never heard of. That is how seemingly innocent updates cause production incidents: the change log you did not read belongs to a package you did not know you had.
Ownership here means auditing what you actually ship. Review the audit output monthly, pin what matters, and remove direct dependencies you no longer use so their transitive trees leave with them. When a security advisory lands, you want a short list of owners and reasons, not a thousand packages with no provenance.
This is also where production observability pays for itself. Our Sentry error tracking guide for React Native production covers catching the crashes that dependency bumps cause before your users file them.
Maintenance is the scaling wall
Every builder wants production in a weekend. Six months later, maintenance is the real bill. AI tools optimize for first ship, not year-two support. Dependency rot compounds: every unpinned version, every abandoned package, every workaround the model scribbled into a comment.
The moment library is the canonical example. It is routinely included by generators, it works fine on day one, and it has been in maintenance mode for years. Keeping it means carrying legacy weight; replacing it means touching every date call in the app. Neither option is hard on its own. Discovering the choice during a security review, under deadline, is what hurts.
The pattern repeats with navigation majors, deprecated pickers, and abandoned UUID helpers. The upgrade that breaks deep linking and forces a three-screen rewrite is not a model failure — it is a maintenance failure that started the day the package was added without a rationale. The model is not your bottleneck. Your package.json is.
Own your package dot json
The only way through dependency hell is ownership: pin versions, document why each library exists, and keep upgrades boring. AI can scaffold, but it cannot guarantee what happens when the next Expo major drops or a maintainer archives a package your auth flow depends on.
A minimal ownership routine that actually holds:
# monthly, in CI or on a calendar reminder
npm audit
npm outdated
npx expo install --checkPair that with a short decision log. A DECISIONS.md entry or a comment next to each non-obvious dependency — what it does, why this one, when to revisit — turns the next upgrade from archaeology into reading. Pin everything through the lockfile, commit it, and treat Dependabot-style noise as a signal to curate rather than click through.
Compare the two manifests below. The first is illustrative of generator output: floating ranges, no peers, no rationale. The second mirrors how official templates ship: matched versions that move with the SDK.
// Illustrative AI-generated manifest: floats, no peers, no reasons
{
"dependencies": {
"expo": "~50.0.0",
"react-native-paper": "^5.10.0"
}
}// Template-style manifest: versions matched to the SDK release
{
"dependencies": {
"expo": "~50.0.0",
"react-native": "0.73.4",
"react-native-gesture-handler": "~2.12.0",
"react-native-reanimated": "~3.7.0"
}
}Transparency is the difference, not model smarts. Prefer starters and kits that show you the stack up front. OTF kits ship with the dependency list visible and the versions pinned, so your agent builds on ground you have already inspected. Browse them at OTF templates before your next scaffold — starting from an owned stack beats auditing a mystery one.
Dependency intelligence dashboards like Package Intelligence are worth adding to that routine. Let the report find the risk, then do the human work: remove what you cannot justify, pin what you keep, and write down why. The code you own is the only code you can maintain.
Sources
- Introducing Package Intelligence: dependency intelligence for React Native and Expo teams — feature list and positioning for the dependency health, compatibility, bundle impact, and risk dashboard cited throughout.
- Expo documentation — official docs home confirming the single JavaScript and TypeScript project model, official templates, and pinned native modules referenced for template hygiene.
Stop wiring. Start shipping.
- Login, database, and backend already connected — nothing to set up
- iOS + Android + web from one codebase
- AI configs pre-tuned + 20+ task prompts per kit included