
How We Scaled a React Native Codebase to 200,000 Lines Without Losing Developer Velocity
- Larry Brooks
- Software, Strategy
- 21 May, 2026
At 20,000 lines, our React Native app was a joy to work on. At 80,000 lines, builds took 4 minutes and developers stepped on each other's changes daily. At 120,000 lines, we stopped and restructured. At 200,000 lines, developer velocity was higher than it had been at 50,000.
The difference was not better developers. It was better boundaries.
The Problem With Flat Architecture
Most React Native projects start with a flat structure: components, screens, services, utils. This works beautifully at small scale. Every developer understands the entire codebase. Navigation between files is intuitive. Refactoring is straightforward.
At scale, flat architecture creates invisible coupling. A "shared" utility function gets imported by 47 files. A "common" component accumulates 23 props to serve 15 different use cases. A change to the user service cascades through screens that the developer did not know existed. Pull request reviews become archaeological expeditions.
The Module Boundary System
We restructured into a monorepo with strict module boundaries. Each business domain — authentication, payments, messaging, profile, onboarding — became an independent module with its own components, state management, API layer, and tests.
Modules communicate through defined interfaces. The authentication module exports a useAuth hook and an AuthGuard component. It does not export its internal state structure, its API client, or its storage implementation. Other modules consume the interface without depending on the implementation.
This boundary enforcement is not just organizational — it is enforced by our build system. A module cannot import from another module's internal files. The only legal imports are from the module's public API, defined in an index file. Violations fail the build.
The Monorepo Tooling
We use Turborepo for build orchestration and caching. When a developer changes the payments module, only the payments module and its dependents rebuild. The authentication module, the messaging module, and every other unaffected module uses cached build artifacts. Build time for a typical change went from 4 minutes to 45 seconds.
Each module has its own test suite that runs independently. A developer working on payments runs payments tests in 12 seconds. The full test suite — which CI runs on every pull request — still takes 3 minutes, but no individual developer waits for it during development.
The Team Impact
Module boundaries create team boundaries. The payments team owns the payments module. They can refactor its internals, update its dependencies, and restructure its architecture without coordinating with other teams — as long as the public API does not change.
This ownership model eliminated the daily merge conflicts, reduced code review scope by 60%, and allowed us to onboard new developers in 3 days instead of 3 weeks. A new developer learns their module, not the entire codebase.
When to Restructure
If your team spends more time coordinating changes than making them, your architecture has become a bottleneck. Restructuring is expensive — our migration took 6 weeks — but the cost of not restructuring compounds with every developer you add and every feature you ship.
If your React Native codebase is slowing your team down, let's design the architecture that speeds them up.
