We wanted to add an innovative feature to a client’s React Native app. The library existed. The integration looked straightforward.
Three months later, the feature is on the back burner and the client is wondering what’s taking so long.
The problem wasn’t the library. It was everything the library touched.
Version Gridlock
The new library required a newer version of Xcode and Swift. Reasonable — Apple moves fast, libraries follow.
But our app used Lottie for animations. And our version of Lottie wouldn’t compile with the newer Xcode.
This is how you discover these things: you bump a version number, run a build, and watch Xcode throw errors in code you didn’t write. The library’s GitHub issues confirm it — yes, this is a known problem, yes, a fix is coming, no, there’s no timeline.
So: upgrade Lottie? Their newer versions had breaking API changes. We’d need to audit every animation in the app, update the integration code, and regression test screens we hadn’t planned to touch.
Downgrade the new library? The features we needed weren’t in older versions.
The dependency graph had us pinned. Three libraries, each fine on their own, each maintained by different people with different priorities, refusing to coexist.
We decided to rip out Lottie entirely. But by then, weeks had passed. The delays pushed the whole feature down the priority list. The client saw a stalled roadmap. We saw a version conflict we couldn’t have predicted at install time.
This is the cost that doesn’t show up in your package.json. Not bundle size. Not install time. The cost is organizational: explaining to stakeholders why a "simple integration" turned into a quarter of lost momentum.
The Fork Tax
I inherited a forked dependency in another project. A previous developer needed one small change — maybe a bug fix, maybe a feature that hadn’t been merged upstream. So they forked the library and pointed package.json at their fork.
That was 20 commits ago.
Now the fork is behind mainline. The original library has bug fixes we don’t have. Security patches, maybe. I don’t know, because evaluating whether I can safely merge 20 commits into a fork I didn’t create isn’t a task I have time for.
So the fork sits there. It works. I don’t touch it. And every time I look at it, I know there’s a small pile of risk I’m ignoring because the cost of addressing it is higher than the cost of pretending it doesn’t exist.
The original sin was small: one change, fork the repo, move on. But dependencies aren’t static. The moment you fork, you’re not borrowing anymore — you’re owning. And ownership has carrying costs that compound over time.
Native Tooling Landmines
We integrated OneSignal for push notifications. The JavaScript side was fine. The native side was not.
Something in their installation process broke our Xcode configuration. The app still builds. The app still runs. But when we launch from Xcode, we get an error: Xcode can’t connect to the app, or the connection was lost.
No console. No breakpoints. No debugging.
The app works fine — we can build, deploy, test functionality. But our development environment is degraded. Somewhere in the OneSignal setup, something changed that Xcode doesn’t like, and we haven’t had time to hunt it down.
So we work around it. We use console logs that show up in Metro instead of Xcode. We test on the simulator more than we’d like. The friction is small but constant.
React Native’s promise is that you write JavaScript. But every native module is a reminder that you’re standing on two platforms with their own toolchains, their own configuration formats, their own ways of breaking silently. When a native dependency breaks something, you’re debugging in environments you didn’t sign up for — or, more often, you’re just living with the damage.
The Bet You’re Making
I’m not going to tell you to avoid dependencies. That’s not practical. React Native without libraries is React Native without navigation, without state management, without half the features your app needs.
But every dependency is a bet. You’re betting that the maintainer’s roadmap will align with yours. You’re betting they’ll keep up with React Native’s upgrade cycle. You’re betting that when Apple or Google changes something, someone will fix it before your deadline.
Sometimes you win that bet. A well-maintained library saves you months of work and keeps pace with the ecosystem.
Sometimes you lose. And the loss isn’t just engineering time — it’s explaining to stakeholders why the roadmap slipped, it’s carrying forked code you don’t have time to maintain, it’s working around broken tooling because fixing it isn’t the priority.
Before you install, ask: what happens if this library falls behind? What happens if it conflicts with something else? How deep into native code will I have to go if something breaks?
You won’t always have good answers. But at least you’ll know what you’re betting on.