DEV Community

José Vivas
José Vivas

Posted on

Monorepos in Flutter: Scaling Shared Code Without Losing Your Mind

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, or flutter_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/ and packages/ 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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*"
Enter fullscreen mode Exit fullscreen mode

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 more

  • Testing Pipelines
    Combine melos 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)