
Monorepo or Polyrepo? Organizing Cross-Platform Codebases properly

Overview
The way we organize code repositories fundamentally shapes development workflows, team collaboration patterns, and technical architecture. For cross-platform mobile applications, this organizational decision carries even greater significance as teams navigate multiple platforms, shared components, and specialized platform requirements. The longstanding debate between monorepo (a single repository containing multiple projects) and polyrepo (multiple repositories for different projects) approaches has evolved significantly as tools mature and team structures adapt to changing development practices. In 2025, both approaches remain viable, but the considerations for selecting the right structure have grown more nuanced, particularly for mobile projects spanning iOS, Android, and web platforms.
While repository organization might seem like a purely technical decision, its implications extend far beyond code storage. The choice fundamentally affects continuous integration pipelines, deployment strategies, dependency management, and even team communication patterns. Mobile development teams face unique challenges including native module integration, platform-specific code organization, and coordinating releases across app stores with different review processes. The repository structure you choose can either amplify these challenges or help mitigate them. This article explores the practical realities of both monorepo and polyrepo approaches for cross-platform mobile development in 2025, providing concrete examples and decision frameworks to help teams make informed choices that support long-term productivity and codebase health.
Understanding Repository Structures
Before evaluating the merits of different approaches, it's essential to clearly define what we mean by monorepo and polyrepo structures and how they apply specifically to mobile application development.
Monorepo Structure
A monorepo (monolithic repository) contains multiple distinct projects—such as applications, libraries, and tools—within a single version control repository. In the mobile context, this typically means:
- Platform-specific application code (iOS, Android, web) lives alongside shared code
- Backend services that support the mobile applications may coexist in the same repository
- Developer tools, scripts, and configuration are centrally managed
- Documentation covers all aspects of the system in one place
A typical monorepo for a cross-platform mobile project might have a directory structure like:
company-mobile/
├── apps/
│ ├── ios/ # Native iOS app
│ ├── android/ # Native Android app
│ ├── web/ # Web version
│ └── admin-portal/ # Internal admin tools
├── packages/
│ ├── core/ # Shared business logic
│ ├── ui-components/ # Shared UI components
│ ├── api-client/ # API communication layer
│ └── analytics/ # Analytics integration
├── tools/
│ ├── generators/ # Code generators
│ └── scripts/ # Build and deployment scripts
├── docs/
│ ├── architecture/
│ └── api-specs/
└── package.json # Workspace definition
This structure places related projects together, facilitating global changes and coordination while still maintaining logical separation between components.
Polyrepo Structure
A polyrepo (multiple repository) approach distributes related projects across separate version control repositories. For mobile applications, this typically means:
- Each platform-specific application has its own dedicated repository
- Shared libraries exist in their own repositories and are consumed as dependencies
- Backend services live in separate repositories with their own lifecycle
- Documentation may be split across repositories or centralized elsewhere
A typical polyrepo setup for the same cross-platform mobile project might look like:
company-ios-app/ # iOS application repository
company-android-app/ # Android application repository
company-web-app/ # Web application repository
company-admin-portal/ # Admin portal repository
company-core-sdk/ # Shared business logic repository
company-ui-components/ # Shared UI components repository
company-api-client/ # API client repository
company-mobile-docs/ # Centralized documentation repository
Each repository focuses on a specific concern, with clear boundaries and independent versioning. Dependencies between projects are explicitly declared and managed through package managers or other dependency mechanisms.
Hybrid Approaches
In practice, many teams implement hybrid approaches that combine elements of both models. Common hybrid patterns include:
Platform monorepos with shared libraries: Separate repositories for each platform, with shared code in dedicated repositories consumed as dependencies
Feature-based monorepos: Multiple monorepos organized around major features or business domains rather than technical boundaries
Submodule/subtree integration: Using Git submodules or subtrees to incorporate external repositories within a larger repository structure
These hybrid approaches attempt to balance the benefits of each model, though they also introduce their own complexity in terms of tooling and workflow.
Monorepo Benefits and Challenges
The monorepo approach offers several distinct advantages for cross-platform mobile development, along with challenges that teams must address.
Benefits of Monorepos
Atomic Cross-Platform Changes
Perhaps the most significant advantage of monorepos for mobile development is the ability to make atomic changes across multiple platforms and components:
# In a monorepo, a single commit can update all platforms
git commit -m "Implement user profile across all platforms"
This enables coordinated feature development with synchronized versioning, particularly valuable when implementing features that span multiple platforms. For example, adding a new authentication mechanism can be implemented, tested, and verified across iOS, Android, and shared code in a single pull request.
Simplified Dependency Management
Monorepos dramatically simplify dependency management between related projects. When shared components are updated, applications within the monorepo automatically use the latest versions:
// In a monorepo package.json, local dependencies are simple
{
"dependencies": {
"@company/core": "workspace:*",
"@company/ui-components": "workspace:*"
}
}
This eliminates the "dependency hell" that can occur when managing versioned packages across repositories. For mobile applications that share business logic, networking layers, or UI components, this simplified dependency model reduces coordination overhead and prevents version conflicts.
Unified CI/CD and Testing
Monorepos enable holistic testing and deployment pipelines that can verify changes across all affected components:
# CI pipeline can easily target affected packages
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Find affected packages
id: affected
run: node ./tools/scripts/find-affected.js
- name: Test affected packages
run: npm test --filter=${{ steps.affected.outputs.packages }}
This is particularly valuable for mobile projects where changes in shared code might affect multiple platforms. Test coverage can span platform boundaries, catching integration issues early that might otherwise only surface during manual testing.
Challenges of Monorepos
Repository Size and Performance
As monorepos grow, they can become unwieldy, leading to slower Git operations and increased storage requirements:
# Cloning a large monorepo can take significant time
git clone https://github.com/company/mobile-monorepo.git
# Downloading 2.1 GB...
For mobile projects that include large binary assets, native modules with compiled code, and multiple platform-specific codebases, repository size can quickly become challenging. This is exacerbated when the repository includes historical large binary files that have been modified many times.
Build System Complexity
Building cross-platform applications in a monorepo requires sophisticated build systems that understand dependencies between projects:
// Example Nx build configuration for targeting affected projects
module.exports = {
affected: {
target: "build",
parallel: 3,
dependents: true,
},
};
Setting up and maintaining these build systems requires significant investment, especially for mobile projects with platform-specific build requirements like Xcode for iOS and Gradle for Android.
Permission and Access Control
Monorepos make fine-grained access control more challenging, as repository permissions apply across all projects:
# In a monorepo, repository-level permissions apply to everything
gh repo set-access company/mobile-monorepo ADMIN mobile-team
For organizations with specialized teams or strict access control requirements (such as regulated industries), this can create security and compliance challenges. Mobile projects often involve platform specialists who should have access to specific parts of the codebase but not necessarily everything.
Polyrepo Benefits and Challenges
The polyrepo approach offers different advantages and challenges for cross-platform mobile development teams.
Benefits of Polyrepos
Team Autonomy and Ownership
Separate repositories naturally align with team boundaries, enabling clear ownership and independent workflows:
# Teams can work independently with their own release cycles
cd company-ios-app
git tag v2.5.0
git push origin v2.5.0
This is particularly valuable for platform-specific teams who can work at their own pace, following platform-specific best practices without coordination overhead. For example, an iOS team can adopt Swift UI features without waiting for equivalent Android implementations.
Focused Codebases and Documentation
Each repository contains only what's relevant to its specific domain, making codebases more navigable:
company-ios-app/
├── App/
│ ├── Features/
│ │ ├── Authentication/
│ │ ├── Home/
│ │ └── Profile/
├── Tests/
├── Fastlane/
└── README.md # iOS-specific documentation
For mobile projects where platform-specific considerations like store guidelines, certification requirements, and testing approaches can differ significantly, this focused structure helps developers find relevant information quickly without wading through unrelated documentation.
Independent Scaling and Performance
Each repository can be optimized for its specific requirements without affecting other projects:
# Heavy optimization in one repo doesn't affect others
cd company-android-app
git gc --aggressive
git lfs prune
This becomes important as projects grow, particularly for mobile applications that may include large assets or platform-specific libraries. Teams can implement repository-specific optimizations without coordination across all projects.
Challenges of Polyrepos
Cross-Platform Feature Coordination
Implementing features that span multiple platforms requires careful coordination across repositories:
# In polyrepos, changes must be made separately in each repository
cd company-ios-app
git commit -m "Implement user profile for iOS"
cd ../company-android-app
git commit -m "Implement user profile for Android"
cd ../company-core-sdk
git commit -m "Add user profile models to SDK"
This introduces significant overhead for ensuring feature parity and consistent behavior across platforms. Mobile teams must implement additional processes for tracking cross-repository changes and ensuring synchronized releases.
Dependency Version Management
Managing dependencies between separate repositories requires explicit versioning and updates:
// In polyrepos, explicit versioning is required
{
"dependencies": {
"@company/core": "^2.3.1",
"@company/ui-components": "^1.7.0"
}
}
This creates additional overhead for keeping dependencies updated and handling breaking changes. For rapidly evolving mobile projects, this can lead to version conflicts and integration challenges when components evolve at different rates.
Fragmented CI/CD and Testing
Each repository typically has its own CI/CD pipeline, making it challenging to test interactions between components:
# Limited to testing within a single repository
name: iOS CI
on: [push, pull_request]
jobs:
test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Run tests
run: xcodebuild test -scheme CompanyApp
For mobile applications where integration testing across platforms is crucial, this fragmentation makes comprehensive testing more difficult. Teams must implement additional integration testing environments or rely more heavily on manual testing to catch cross-platform issues.
Real-World Project Structures
Examining concrete project structures helps illustrate how these approaches work in practice for different mobile frameworks.
Flutter Monorepo Structure
Flutter projects benefit from a monorepo approach when sharing code across multiple applications. Here's a typical structure:
flutter-monorepo/
├── apps/
│ ├── customer_app/ # Main customer-facing application
│ │ ├── android/ # Android-specific code
│ │ ├── ios/ # iOS-specific code
│ │ └── lib/ # Flutter application code
│ ├── delivery_app/ # Delivery partner application
│ │ ├── android/
│ │ ├── ios/
│ │ └── lib/
│ └── admin_portal/ # Web-based admin portal
│ └── lib/
├── packages/
│ ├── core/ # Shared business logic
│ │ └── lib/
│ ├── ui_kit/ # Shared UI components
│ │ └── lib/
│ ├── api_client/ # API communication
│ │ └── lib/
│ └── analytics/ # Analytics implementation
│ └── lib/
├── tools/
│ ├── code_generators/ # Build-time code generation
│ └── release_scripts/ # Release automation
├── melos.yaml # Monorepo management configuration
└── README.md
This structure leverages Dart's package system with tools like Melos for monorepo management. Flutter's cross-platform nature makes a monorepo particularly effective as much of the code can be shared directly across platforms without adaptation.
Sample melos.yaml configuration:
name: flutter_monorepo
packages:
- apps/**
- packages/**
scripts:
analyze:
run: melos exec -- "flutter analyze"
description: Run Flutter analyzer on all packages
test:
run: melos exec -- "flutter test"
description: Run tests in all packages
packageFilters:
dirExists:
- test
build_all:
run: melos run build --no-select
description: Build all apps
build:
run: flutter build apk --release
description: Build a specific app
packageFilters:
scope: "apps/*"
React Native Polyrepo Structure
For React Native projects, a polyrepo approach might be organized as follows:
react-native-ios/ # iOS application
├── ios/ # Native iOS code
├── src/
│ ├── features/
│ │ ├── auth/
│ │ ├── home/
│ │ └── profile/
│ ├── navigation/
│ └── App.tsx
├── package.json
└── README.md
react-native-android/ # Android application
├── android/ # Native Android code
├── src/
│ ├── features/
│ │ ├── auth/
│ │ ├── home/
│ │ └── profile/
│ ├── navigation/
│ └── App.tsx
├── package.json
└── README.md
react-native-core/ # Shared business logic
├── src/
│ ├── api/
│ ├── models/
│ └── utils/
├── package.json
└── README.md
react-native-ui/ # Shared UI components
├── src/
│ ├── components/
│ ├── themes/
│ └── hooks/
├── storybook/ # Component documentation
├── package.json
└── README.md
This structure separates platform-specific implementations while sharing common code through npm packages. Each repository has its own package.json with explicit dependencies:
// react-native-ios/package.json
{
"name": "@company/ios-app",
"version": "1.2.0",
"dependencies": {
"@company/core": "^3.1.0",
"@company/ui": "^2.4.0",
"react": "18.3.0",
"react-native": "0.74.0"
}
}
// react-native-core/package.json
{
"name": "@company/core",
"version": "3.1.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
}
}
.NET MAUI Hybrid Approach
For .NET MAUI projects, a hybrid approach often works well, with platform-specific extensions in separate repositories:
maui-main/ # Main application monorepo
├── src/
│ ├── App/ # MAUI application
│ │ ├── Pages/
│ │ ├── ViewModels/
│ │ ├── Services/
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ ├── iOS/
│ │ │ ├── MacCatalyst/
│ │ │ └── Windows/
│ │ └── App.xaml
│ ├── Core/ # Core business logic
│ │ ├── Models/
│ │ ├── Repositories/
│ │ └── Services/
│ └── UI/ # Shared UI components
│ ├── Controls/
│ └── Themes/
├── tests/
│ ├── App.Tests/
│ └── Core.Tests/
└── Directory.Build.props # Common build properties
maui-native-ios/ # iOS-specific extensions
├── src/
│ └── NativeFeatures/
├── samples/
└── README.md
maui-native-android/ # Android-specific extensions
├── src/
│ └── NativeFeatures/
├── samples/
└── README.md
The main application uses a monorepo structure for the cross-platform code, while platform-specific extensions that require deep native integration are maintained in separate repositories. This hybrid approach balances the benefits of both models, providing centralized management for shared code while allowing platform specialists to work independently on native extensions.
Decision Framework
Selecting the right repository structure for a cross-platform mobile project requires evaluating several key factors:
Team Structure and Expertise
Specialized platform teams: If your organization has dedicated iOS, Android, and web teams with platform-specific expertise, a polyrepo approach may align better with team boundaries.
Feature-based teams: If your teams are organized around features rather than platforms, a monorepo simplifies cross-platform feature implementation.
Team size and distribution: Larger, distributed teams often benefit from the explicit contracts and boundaries of polyrepos, while smaller, co-located teams can leverage the tighter integration of monorepos.
Technical Architecture
Code sharing percentage: If your application shares significant code across platforms (>50%), a monorepo simplifies this sharing. For projects with minimal shared code, separate repositories reduce unnecessary coupling.
Framework selection: Native frameworks often benefit from polyrepos due to different toolchains, while cross-platform frameworks like Flutter and React Native can leverage monorepos for code sharing.
Deployment independence: If platforms have independent release cycles (e.g., web deploys continuously while mobile releases monthly), polyrepos may provide better support for diverse workflows.
Organizational Factors
Security and compliance: Organizations with strict access control requirements may find polyrepos easier to secure, with clear permission boundaries.
Onboarding and knowledge sharing: Monorepos can simplify onboarding by providing a comprehensive view of the system, while polyrepos create focused learning paths for platform specialists.
Long-term maintenance: Consider how your chosen structure will scale as the application grows and team composition changes over time.
Decision Matrix
| Factor | Favors Monorepo | Favors Polyrepo |
|---|---|---|
| Team Organization | Feature-based teams | Platform-based teams |
| Code Sharing | High percentage of shared code | Low percentage of shared code |
| Release Cadence | Synchronized releases | Independent release cycles |
| Scale | Smaller codebase and team | Large codebase or distributed teams |
| Access Control | Minimal security restrictions | Fine-grained access requirements |
| Development Focus | Feature consistency across platforms | Platform-specific optimization |
| Tooling Investment | Able to invest in custom tooling | Limited resources for tooling |
Tooling and Infrastructure
Modern tools have significantly improved the feasibility of both approaches in 2025, addressing many of the historical challenges.
Monorepo Tooling
Several tools now make managing large monorepos more practical for mobile development:
- Nx provides advanced dependency analysis and selective rebuilds:
# Only build and test what's affected by recent changes
nx affected --target=test
nx affected --target=build
- Turborepo offers incremental builds and remote caching:
# Leverage distributed caching for faster builds
turbo build --filter=app-ios... --cache-dir=.turbo
- Git LFS manages large binary assets efficiently:
# Track platform-specific binary files with Git LFS
git lfs track "*.framework"
git lfs track "*.aar"
- Sparse checkout reduces local storage requirements:
# Clone only the parts of the monorepo you need
git clone --filter=blob:none --sparse https://github.com/company/monorepo
cd monorepo
git sparse-checkout set apps/ios
Polyrepo Tooling
Tools for managing multiple repositories have also evolved:
- GitHub's Multi-Repository Projects provide visibility across repositories:
# Create a project that spans multiple repositories
gh project create --title "Q2 Mobile Release" --repositories "company/ios-app,company/android-app,company/core-sdk"
- Changesets manage versioning and changelogs across packages:
# Create a changeset that affects multiple packages
changeset
# Version packages based on changesets
changeset version
- Meta coordinates work across multiple repositories:
# Clone all related repositories
meta git clone git@github.com:company/mobile-meta.git
# Run commands across all repositories
meta exec "git checkout main && git pull"
- Private NPM registries (or similar for other languages) simplify dependency management:
// package.json
{
"publishConfig": {
"registry": "https://npm.company.com"
}
}
CI/CD Considerations
Repository structure significantly impacts CI/CD pipelines for mobile applications:
- Monorepo CI optimization focuses on selective testing and building:
# GitHub Actions workflow with selective execution
jobs:
determine_scope:
runs-on: ubuntu-latest
outputs:
ios_affected: ${{ steps.affected.outputs.ios }}
android_affected: ${{ steps.affected.outputs.android }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- id: affected
run: node ./tools/ci/detect-affected-apps.js
build_ios:
needs: determine_scope
if: ${{ needs.determine_scope.outputs.ios_affected == 'true' }}
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- run: cd apps/ios && fastlane build
- Polyrepo CI coordination requires orchestration across repositories:
# GitHub Actions workflow with repository dispatch
name: Trigger Downstream Builds
on:
push:
branches:
- main
paths:
- "src/**"
jobs:
notify_dependents:
runs-on: ubuntu-latest
steps:
- name: Trigger iOS build
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.PAT }}
repository: company/ios-app
event-type: core-update
client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
Team Organization Considerations
Repository structure and team organization are deeply intertwined, each influencing the other.
Conway's Law and Repository Structure
Conway's Law—"organizations design systems that mirror their communication structure"—is particularly relevant to repository organization. Teams should consider:
Alignment with communication patterns: Repository boundaries often become communication boundaries; ensure they reflect how your teams actually collaborate.
Ownership and accountability: Clear ownership is crucial for quality and maintenance; repository structure should support, not hinder, accountability.
Evolution over time: As teams grow and reorganize, repository structures must adapt; consider how flexible your chosen approach will be.
Collaboration Patterns
Different repository structures enable different collaboration patterns:
- Cross-platform feature development is often smoother in monorepos, where a single pull request can implement a feature across platforms:
# A single PR can contain changes across platforms
git checkout -b feature/user-profile
# Make changes to iOS, Android, and shared code
git add .
git commit -m "Implement user profile feature across all platforms"
- Platform specialization may be more natural in polyrepos, where experts can focus on their domain:
# iOS experts work in the iOS repository
cd company-ios-app
git checkout -b feature/ios-specific-enhancements
# Make iOS-specific improvements
- Dependency management workflows differ significantly:
# In monorepos, dependencies are updated in one place
cd monorepo
npm install --save-exact important-package@2.0.0
git commit -m "Update important-package to 2.0.0 across all apps"
# In polyrepos, updates require coordination
cd company-ios-app
npm install --save-exact important-package@2.0.0
git commit -m "Update important-package to 2.0.0"
# Repeat for each repository
Summary
The choice between monorepo and polyrepo approaches for cross-platform mobile development in 2025 remains contextual rather than universal. Each approach offers distinct advantages and challenges that must be evaluated against your team's specific circumstances and priorities.
Monorepos excel at facilitating cross-platform feature development, simplifying dependency management, and enabling comprehensive testing. They're particularly valuable for teams focused on feature consistency across platforms and for projects using cross-platform frameworks with significant shared code. However, they require investment in tooling for performance and build optimization, and they may create challenges for security-sensitive organizations that require fine-grained access control.
Polyrepos provide clear boundaries that align well with specialized platform teams, enable independent scaling and optimization, and support diverse release cycles. They're particularly effective for organizations with platform-specific teams and projects where platforms have distinct requirements and timelines. However, they introduce coordination overhead for cross-platform features and require additional infrastructure for managing dependencies and ensuring consistent releases.
Hybrid approaches continue to emerge that combine elements of both models, such as using monorepos for closely related components while maintaining separation for specialized or independently evolving subsystems. These hybrids can offer "best of both worlds" solutions when implemented thoughtfully.
When selecting an approach for your team, consider starting with these questions:
- How is your team organized—by platform or by feature?
- How much code is truly shared across platforms?
- How synchronized are your release cycles across platforms?
- What are your security and access control requirements?
- How much can you invest in tooling and infrastructure?
The most successful mobile teams in 2025 aren't dogmatically committed to either approach but instead pragmatically select and adapt repository structures that support their specific development workflows, team organization, and business requirements. By understanding the trade-offs and leveraging modern tooling, teams can implement either approach effectively while mitigating its inherent challenges.
Ready to streamline your internal app distribution?
Start sharing your app builds with your team and clients today.
No app store reviews, no waiting times.