One Repo, Two Platforms: Sharing Code Between Next.js and React Native
One Repo, Two Platforms: Sharing Code Between Next.js and React Native
Building for web and mobile from a unified codebase is no longer aspirational—it is a pragmatic path to velocity and consistency. This article explains how teams can share code between Next.js and React Native using a monorepo, compares Nx and Turborepo, outlines code-sharing patterns, discusses CI/CD, highlights pitfalls, and proposes a robust testing strategy. If you are evaluating architecture for a production system, our team can help you plan and implement at scale—see Next.js services, DevOps enablement, and front-end development services.
Why a monorepo for web and mobile?
Historically, industry leaders have used monorepos to coordinate vast codebases. Google describes managing billions of lines of code in a single repository to enable unified tooling and consistent practices across teams, languages, and services (CACM). Facebook similarly detailed scaling a single source-of-truth repository to sustain rapid iteration (Facebook Engineering). For product teams shipping both web and mobile, monorepos amplify these benefits: a shared design system, common business logic, centralized CI/CD and governance, and deterministic versioning across platforms.
Core structure and code sharing patterns
A pragmatic structure keeps apps separate yet encourages shared libraries:
repo/
apps/
web/ # Next.js app
mobile/ # React Native (often Expo) app
packages/
ui/ # cross-platform components (via react-native-web)
theme/ # design tokens, colors, spacing, typography
data/ # business logic, API SDKs, validation
utils/ # shared TypeScript utilities
tooling/ # linters, custom scripts
tsconfig.base.json
package.json
Key techniques:
- Use Yarn workspaces or pnpm workspaces for dependency hoisting and local package linking.
- Share UI via react-native-web so React Native primitives render in Next.js.
- Share business logic using TypeScript libraries and project references for fast, incremental builds.
- Expose design tokens (colors, spacing, typography) through a platform-agnostic package consumed by both apps.
Comparing Nx and Turborepo for Next.js + React Native
Nx
Nx is a full-featured build system and dev platform with a project graph, task orchestration, generators, and plugins. It provides incremental, parallelized builds and powerful dependency-aware commands (e.g., only run affected targets). Official and community plugins cover React, Next.js, and React Native, plus Storybook, Cypress, and more. Nx Cloud adds distributed caching and task execution. See Nx documentation and Nx Cloud.
- Pros: rich generators, affected graph, integrated test/build/lint pipelines, opinionated structure, strong large-team ergonomics.
- Cons: steeper learning curve; React Native support often relies on community plugins; more configuration upfront.
Turborepo
Turborepo focuses on high-speed monorepo builds with pipeline definitions, hashing, and remote caching. It is light, fast to adopt, and pairs naturally with Next.js. Remote caching via Vercel makes CI pipelines notably quicker for unchanged tasks. See Turborepo docs and remote caching guidance here.
- Pros: minimal setup, blazing-fast caching, straightforward pipelines, excellent fit for Next.js.
- Cons: fewer built-in generators and graph-aware features compared to Nx; you compose more tooling yourself.
Design system: one language for two platforms
A shared design system ensures consistent brand and usability across web and mobile. Define tokens (colors, typography, spacing) in a neutral format and export platform bindings. The Design Tokens Community Group outlines vendor-agnostic approaches. In code, standardize on React Native primitives with react-native-web for the web, and isolate platform-specific adaptations in thin wrappers (e.g., file suffixes like Button.native.tsx vs Button.web.tsx). Documentation and Storybook can live inside the repo, with stories consuming tokens directly for fidelity.
Tooling choices that pay off
Success hinges on predictable, fast, and consistent tooling. Choose pnpm or Yarn workspaces, adopt TypeScript project references, and enforce a single ESLint/Prettier config at the root. For Metro (React Native), ensure the resolver follows symlinks and transpiles shared packages; for Next.js, align Babel/TS configs to compile shared code. Expo’s monorepo guide (Expo docs) and Next.js guidance (Next.js docs) illustrate common gotchas.
CI/CD: fast feedback and reliable releases
CI/CD impacts delivery performance measured by the DORA metrics—lead time, deployment frequency, change failure rate, and time to restore (Google DORA report). Monorepos help by targeting only affected areas and leveraging remote caching.
Example Turborepo pipeline (turbo.json):
{
'$schema': 'https://turborepo.org/schema.json',
'pipeline': {
'build': { 'dependsOn': ['^build'], 'outputs': ['dist/**'] },
'test': { 'dependsOn': ['^build'] },
'lint': {}
}
}
Example Nx workflow snippet:
# Build only affected projects from main to the current HEAD
nx affected --target=build --base=origin/main --head=HEAD
nx affected --target=test --parallel
For deployment: web goes to Vercel or your cloud of choice; mobile builds flow through EAS/Expo, App Store Connect, and Google Play. Cache Node/PNPM/Yarn in CI, enable Nx Cloud or Turborepo remote caching, and gate releases with automated tests. If you need help designing pipelines, explore our DevOps services.
Pitfalls and how to avoid them
- Bundler mismatch: Next.js uses Webpack/Turbopack; React Native uses Metro. Mitigation: keep shared packages transpiled to plain JS; configure Metro to include workspace packages.
- Native module drift: iOS/Android SDK versions can get out of sync. Mitigation: pin versions; use Expo to stabilize the native layer.
- Path/alias confusion: TS path aliases must match Metro and Next. Mitigation: centralize tsconfig paths and mirror them in Metro and Next configs.
- Performance regression: poorly scoped dependencies break caching. Mitigation: keep package manifests tight; configure explicit build outputs; rely on affected commands.
- Design divergence: platform-only components fork design. Mitigation: enforce tokens and shared primitives; document variants in Storybook.
Testing strategy that scales
- Unit tests: Jest for libraries and business logic (Jest).
- Component tests: React Testing Library for Next.js; React Native Testing Library for RN components.
- E2E: Playwright or Cypress for web; Detox for mobile.
- API and contracts: pact-based contract tests (Pact) and realistic API mocking with MSW.
Run tests per package and per app, then aggregate in CI. Use test tags to separate fast feedback (unit) from slower suites (E2E). Gate merges on unit and component tests; gate releases on E2E passes.
Keyword primers
monorepo
A monorepo houses multiple apps and libraries in a single repository, enabling unified standards, shared code, and dependency-aware builds. For web and mobile teams, it centralizes a design system, business logic, and CI/CD, accelerating delivery while reducing drift.
Nx
Nx provides a project graph and powerful affected-commands that run only what changed, plus generators and plugins for React, Next.js, and React Native. It is well-suited for complex, multi-team repos that benefit from opinionated structure and rich tooling (docs).
Turborepo
Turborepo is a fast, minimal monorepo build system with hashing and remote caching. It shines with Next.js apps and keeps configuration small, letting teams assemble their preferred linters, testers, and bundlers (docs).
React Native
React Native enables cross-platform mobile development with native performance. In monorepos, it pairs well with Expo, Metro configured for workspaces, and shared packages that compile down to JavaScript for compatibility (docs, Expo monorepo guide).
Next.js
Next.js is a React framework for production-grade web apps with server rendering, routing, and data-fetching primitives. In monorepos, it consumes shared UI via react-native-web and shared logic libraries for consistent behavior across platforms (docs).
design system
A design system codifies visual language and interaction patterns as tokens, components, and guidelines. Centralizing it in a monorepo ensures web and mobile stay visually cohesive while enabling platform-appropriate adaptations.
tooling
Choose dependable tooling: pnpm or Yarn workspaces, TypeScript project references, ESLint/Prettier, Metro and Next.js alignment, and a build system (Nx or Turborepo) with remote caching. These choices materially affect developer experience and build times.
CI/CD
CI/CD orchestrates builds, tests, and releases. Use affected builds, parallelization, and remote caching to shorten feedback loops, and ensure artifacts for web and mobile are versioned and promoted through consistent stages.
code reuse
Maximize code reuse by extracting shared UI primitives, domain logic, data access, and design tokens into versioned packages. Keep platform-specific facets in thin adapters, allowing most of your code to remain universal.
Putting it into practice
Whether you prefer Nx for its project graph and generators or Turborepo for its lean speed and caching, both approaches can deliver a robust foundation for a two-platform strategy. Start with a clear package boundary plan, invest in a reusable design system, and set up CI/CD that rewards small, frequent changes. For tailored guidance, our team delivers secure, scalable Next.js and React solutions—explore Next.js services, DevOps, and front-end development services.