A key aspect of software development is code sharing—not just utility functions, but also business-critical logic like authentication flows, payment integrations, and domain-specific models. Monorepos help formalize this practice by turning shared code from a "nice-to-have" into a scalable architecture.
In this article, I’ll walk through how to build a production-ready Flutter monorepo that:
- Shares UI components and business logic
- Maintains consistent dependencies across apps and packages
- Streamlines testing and deployment through unified workflows
Why a Monorepo?
When to Choose a Flutter Monorepo
- You're building multiple apps (e.g., customer and admin apps)
- Your team maintains shared packages used across different products
- You need atomic updates, such as rolling out a security patch across all apps simultaneously
- Your CI/CD pipeline benefits from centralized control
When Not to Use a Monorepo
- Small projects that don't require shared code
- Mixed tech stacks, such as teams using both native iOS/Android and Flutter
- Independent release cycles where each app needs isolated versioning and deployment
Pros and Cons
Pros
- Logic and UI reuse: Share entire feature modules—including UI and logic—across apps
-
Unified dependency management: Align versions of libraries like
riverpod
,dio
, orflutter_bloc
- Simplified CI/CD: Trigger tests and builds for all affected packages when shared logic changes
- Cross-project refactoring: Modify shared APIs confidently, knowing all usage is in one place
- Design system consistency: Enforce a shared theme and component library across the organization
Cons
- Versioning complexity: Releasing individual package versions may require tooling like Melos or custom scripts
- Dependency sprawl: A breaking change in a low-level package can affect multiple apps
- Tooling overhead: Requires tools like Melos, shell scripts, or IDE workspace configuration
-
Repository hygiene: A large codebase demands strict conventions (e.g.,
apps/
andpackages/
structure)
Project Structure Setup
Start by defining a clear folder structure for your monorepo:
flutter-monorepo/
├── apps/
│ ├── apps_1/
│ └── apps_2/
├── packages/
│ ├── package_1/
│ └── package_2/
├── melos.yaml
├── pubspec.yaml
└── README.md
You can scaffold your applications with:
flutter create apps/apps_1 --org com.myorg.appname --project-name apps_1
flutter create apps/apps_2 --org com.myorg.appname --project-name apps_2
At the root of the project, define a minimal pubspec.yaml
to include Melos:
name: flutter_monorepo_tutorial
environment:
sdk: ">=3.0.6 <4.0.0"
dev_dependencies:
melos: ^6.0.0
Then configure your melos.yaml
file to register packages and define workspace-wide tooling:
name: flutter_monorepo_tutorial
packages:
- apps/**
- packages/**
command:
bootstrap:
environment:
sdk: ">=3.4.0 <4.0.0"
dependencies:
# Shared runtime dependencies across all apps and packages
# Example:
# provider: ^6.1.1
# dio: ^5.4.0
dev_dependencies:
# Shared development dependencies
# Example:
# flutter_test:
# sdk: flutter
# flutter_lints: ^3.0.0
scripts:
format:all:
description: Format all Dart files to a 120-character line length
run: dart format . -l 120
analyze:all:
description: Run static analysis across all packages and apps
run: flutter analyze .
test:all:
description: Run all tests sequentially
run: flutter test
exec:
orderDependents: true
concurrency: 1
packageFilters:
dependsOn: flutter_test
flutter: true
build:release:
description: Build a release APK for target apps using predefined environment and flavor
run: flutter build apk --release --target=lib/main_prod.dart --dart-define-from-file=.env --flavor=prod
exec:
failFast: true
packageFilters:
scope: "*app*"
Once configured, run melos bootstrap
to install dependencies and link local packages. You can then use the defined scripts to format, analyze, test, and build your workspace consistently.
Wrapping Up
Melos provides a solid foundation for managing Flutter monorepos at scale. A well-structured layout, unified dependency management, and reusable tooling help reduce maintenance overhead and speed up development across teams.
A monorepo setup is not a fit for every team, but when applied in the right context, it becomes a powerful architecture for shared codebases.
More
To go deeper or enhance your monorepo setup, consider exploring the following:
CI/CD with Codemagic
Codemagic supports monorepos natively and allows conditional builds and parallel pipelines. Read moreTesting Pipelines
Combinemelos run
with GitHub Actions (or similar CI tools) to execute tests only for changed packages.Very Good Ventures Templates
Explore production-ready monorepo templates and tooling from Very Good Ventures.Code With Andrea
In-depth tutorials from Code With Andrea cover architecture, modularization, and testing strategies in Flutter.FVM (Flutter Version Management)
Helps medium-to-large teams manage and pin specific Flutter versions per app or package.Learn more
Top comments (0)