Skip to main content

Flutter Project Directory Structures: 17 Architectures and When to Use Them

Β· 7 min read
Flutter Family
Flutter Family Core Team

Explore 17 popular Flutter project directory structures, including Feature-Driven, Clean Architecture, MVVM, BLoC, Riverpod, Vertical Slice, DDD, and Monorepo approaches. Learn how each structure works, its advantages and trade-offs, and which architecture fits your Flutter project.


Here's the collection of common Flutter project directory structures, from simple projects to large-scale production applications.

1. Flat / Simple Structure​

Best for small apps, prototypes, tutorials, and simple utilities.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ screens/
β”‚ β”œβ”€β”€ home_screen.dart
β”‚ β”œβ”€β”€ settings_screen.dart
β”‚ └── profile_screen.dart
β”œβ”€β”€ widgets/
β”‚ β”œβ”€β”€ app_button.dart
β”‚ └── app_card.dart
β”œβ”€β”€ models/
β”‚ └── user.dart
β”œβ”€β”€ services/
β”‚ └── api_service.dart
β”œβ”€β”€ utils/
β”‚ └── helpers.dart
└── constants/
└── app_constants.dart

Characteristics​

  • Very easy to understand
  • Minimal architectural overhead
  • Suitable for small applications
  • Becomes difficult to maintain as the application grows

2. Feature-Driven Structure​

Organizes code around business features rather than technical layers.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ constants/
β”‚ β”œβ”€β”€ errors/
β”‚ β”œβ”€β”€ network/
β”‚ β”œβ”€β”€ routing/
β”‚ β”œβ”€β”€ theme/
β”‚ └── utils/
β”œβ”€β”€ features/
β”‚ β”œβ”€β”€ authentication/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ └── presentation/
β”‚ β”œβ”€β”€ home/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ └── presentation/
β”‚ β”œβ”€β”€ profile/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ └── presentation/
β”‚ └── settings/
β”‚ β”œβ”€β”€ data/
β”‚ β”œβ”€β”€ domain/
β”‚ └── presentation/
└── shared/
β”œβ”€β”€ widgets/
β”œβ”€β”€ models/
└── extensions/

Characteristics​

  • Feature boundaries are clear
  • Easy to scale
  • Features can be developed independently
  • Excellent default for medium and large applications

3. Layer-Driven / Technical-Layer Structure​

Organizes files according to their technical responsibility.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ presentation/
β”‚ β”œβ”€β”€ screens/
β”‚ β”œβ”€β”€ widgets/
β”‚ └── controllers/
β”œβ”€β”€ domain/
β”‚ β”œβ”€β”€ entities/
β”‚ β”œβ”€β”€ repositories/
β”‚ └── use_cases/
β”œβ”€β”€ data/
β”‚ β”œβ”€β”€ models/
β”‚ β”œβ”€β”€ repositories/
β”‚ β”œβ”€β”€ datasources/
β”‚ └── services/
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ constants/
β”‚ β”œβ”€β”€ errors/
β”‚ β”œβ”€β”€ network/
β”‚ β”œβ”€β”€ routing/
β”‚ └── utils/
└── config/
β”œβ”€β”€ environment/
└── app_config.dart

Characteristics​

  • Clear separation of technical responsibilities
  • Works well with Clean Architecture
  • Easy to understand for developers familiar with layered architecture
  • Can become difficult to navigate when many features exist

4. Clean Architecture​

Separates presentation, business logic, and external data sources.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ error/
β”‚ β”œβ”€β”€ network/
β”‚ β”œβ”€β”€ usecases/
β”‚ β”œβ”€β”€ utils/
β”‚ └── constants/
β”œβ”€β”€ features/
β”‚ └── authentication/
β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ datasources/
β”‚ β”‚ β”‚ β”œβ”€β”€ auth_local_datasource.dart
β”‚ β”‚ β”‚ └── auth_remote_datasource.dart
β”‚ β”‚ β”œβ”€β”€ models/
β”‚ β”‚ β”‚ └── user_model.dart
β”‚ β”‚ └── repositories/
β”‚ β”‚ └── auth_repository_impl.dart
β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ β”œβ”€β”€ entities/
β”‚ β”‚ β”‚ └── user.dart
β”‚ β”‚ β”œβ”€β”€ repositories/
β”‚ β”‚ β”‚ └── auth_repository.dart
β”‚ β”‚ └── usecases/
β”‚ β”‚ β”œβ”€β”€ login.dart
β”‚ β”‚ └── logout.dart
β”‚ └── presentation/
β”‚ β”œβ”€β”€ pages/
β”‚ β”œβ”€β”€ widgets/
β”‚ └── bloc/
└── injection_container.dart

Characteristics​

  • Strong separation of concerns
  • Business rules are independent of Flutter/UI
  • Highly testable
  • Suitable for complex applications
  • More boilerplate than simpler structures

5. Clean Architecture + Feature-First​

A common production-oriented combination of feature-first organization and Clean Architecture.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ app/
β”‚ β”œβ”€β”€ app.dart
β”‚ β”œβ”€β”€ router.dart
β”‚ └── theme/
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ constants/
β”‚ β”œβ”€β”€ errors/
β”‚ β”œβ”€β”€ extensions/
β”‚ β”œβ”€β”€ network/
β”‚ β”œβ”€β”€ storage/
β”‚ β”œβ”€β”€ utils/
β”‚ └── widgets/
β”œβ”€β”€ features/
β”‚ β”œβ”€β”€ auth/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ └── presentation/
β”‚ β”œβ”€β”€ home/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ └── presentation/
β”‚ └── settings/
β”‚ β”œβ”€β”€ data/
β”‚ β”œβ”€β”€ domain/
β”‚ └── presentation/
└── di/
└── injection.dart

Characteristics​

This is often a strong choice for large Flutter applications because:

features/
↓
domain
↓
data

presentation
↓
domain

Features remain isolated while the architectural boundaries remain explicit.


6. MVVM Structure​

Uses Model-View-ViewModel.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ models/
β”‚ β”œβ”€β”€ user.dart
β”‚ └── product.dart
β”œβ”€β”€ views/
β”‚ β”œβ”€β”€ home/
β”‚ β”‚ └── home_view.dart
β”‚ β”œβ”€β”€ login/
β”‚ β”‚ └── login_view.dart
β”‚ └── profile/
β”‚ └── profile_view.dart
β”œβ”€β”€ viewmodels/
β”‚ β”œβ”€β”€ home_viewmodel.dart
β”‚ β”œβ”€β”€ login_viewmodel.dart
β”‚ └── profile_viewmodel.dart
β”œβ”€β”€ services/
β”‚ β”œβ”€β”€ api_service.dart
β”‚ └── auth_service.dart
└── repositories/
β”œβ”€β”€ user_repository.dart
└── product_repository.dart

Characteristics​

  • UI is separated from presentation logic
  • ViewModels manage state and UI-facing logic
  • Familiar architecture for developers from other platforms
  • Works well with Provider, Riverpod, ChangeNotifier, etc.

7. MVC Structure​

Uses Model-View-Controller.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ models/
β”‚ β”œβ”€β”€ user.dart
β”‚ └── product.dart
β”œβ”€β”€ views/
β”‚ β”œβ”€β”€ home_view.dart
β”‚ β”œβ”€β”€ login_view.dart
β”‚ └── profile_view.dart
β”œβ”€β”€ controllers/
β”‚ β”œβ”€β”€ auth_controller.dart
β”‚ β”œβ”€β”€ home_controller.dart
β”‚ └── profile_controller.dart
β”œβ”€β”€ services/
β”‚ └── api_service.dart
└── utils/
└── helpers.dart

Characteristics​

  • Simple mental model
  • Good for small-to-medium projects
  • Controllers can become too large if business logic is not separated properly

8. MVI Structure​

Uses Model-View-Intent.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ features/
β”‚ └── login/
β”‚ β”œβ”€β”€ model/
β”‚ β”‚ β”œβ”€β”€ login_state.dart
β”‚ β”‚ └── login_intent.dart
β”‚ β”œβ”€β”€ view/
β”‚ β”‚ └── login_page.dart
β”‚ └── intent/
β”‚ └── login_intent_handler.dart
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ network/
β”‚ └── utils/
└── app/
└── app.dart

Characteristics​

  • State-driven architecture
  • Explicit user intents/actions
  • Useful for complex reactive interfaces
  • Works particularly well with unidirectional data flow

9. BLoC / Cubit Feature Structure​

Organizes BLoC state management around features.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ constants/
β”‚ β”œβ”€β”€ errors/
β”‚ β”œβ”€β”€ network/
β”‚ └── widgets/
β”œβ”€β”€ features/
β”‚ β”œβ”€β”€ auth/
β”‚ β”‚ β”œβ”€β”€ bloc/
β”‚ β”‚ β”‚ β”œβ”€β”€ auth_bloc.dart
β”‚ β”‚ β”‚ β”œβ”€β”€ auth_event.dart
β”‚ β”‚ β”‚ └── auth_state.dart
β”‚ β”‚ β”œβ”€β”€ models/
β”‚ β”‚ β”œβ”€β”€ repositories/
β”‚ β”‚ β”œβ”€β”€ pages/
β”‚ β”‚ └── widgets/
β”‚ β”œβ”€β”€ home/
β”‚ β”‚ β”œβ”€β”€ bloc/
β”‚ β”‚ β”œβ”€β”€ models/
β”‚ β”‚ β”œβ”€β”€ pages/
β”‚ β”‚ └── widgets/
β”‚ └── profile/
β”‚ β”œβ”€β”€ cubit/
β”‚ β”œβ”€β”€ models/
β”‚ β”œβ”€β”€ pages/
β”‚ └── widgets/
└── app/
β”œβ”€β”€ app.dart
└── router.dart

Characteristics​

  • Natural structure for flutter_bloc
  • Keeps state-management code close to its feature
  • Easy to test
  • Avoids one giant global BLoC directory

10. Riverpod Feature Structure​

Organizes Riverpod providers alongside their features.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ app/
β”‚ β”œβ”€β”€ app.dart
β”‚ β”œβ”€β”€ router.dart
β”‚ └── theme/
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ network/
β”‚ β”œβ”€β”€ storage/
β”‚ └── utils/
β”œβ”€β”€ features/
β”‚ β”œβ”€β”€ auth/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ models/
β”‚ β”‚ β”œβ”€β”€ providers/
β”‚ β”‚ β”œβ”€β”€ screens/
β”‚ β”‚ └── widgets/
β”‚ β”œβ”€β”€ products/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ models/
β”‚ β”‚ β”œβ”€β”€ providers/
β”‚ β”‚ β”œβ”€β”€ screens/
β”‚ β”‚ └── widgets/
β”‚ └── cart/
β”‚ β”œβ”€β”€ models/
β”‚ β”œβ”€β”€ providers/
β”‚ β”œβ”€β”€ screens/
β”‚ └── widgets/
└── shared/
└── widgets/

Characteristics​

  • Providers remain close to the state they manage
  • Good fit for Riverpod
  • Scales well with feature-first architecture

11. Repository Pattern​

Separates data access behind repositories.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ models/
β”‚ β”œβ”€β”€ user.dart
β”‚ └── product.dart
β”œβ”€β”€ repositories/
β”‚ β”œβ”€β”€ user_repository.dart
β”‚ └── product_repository.dart
β”œβ”€β”€ datasources/
β”‚ β”œβ”€β”€ remote/
β”‚ β”‚ └── api_datasource.dart
β”‚ └── local/
β”‚ └── database_datasource.dart
β”œβ”€β”€ services/
β”‚ β”œβ”€β”€ api_service.dart
β”‚ └── storage_service.dart
β”œβ”€β”€ screens/
└── widgets/

Characteristics​

Useful when an application has multiple data sources:

UI
↓
Repository
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
Local Remote
Data API

12. Package-by-Feature / Modular Structure​

Useful for very large applications or teams.

packages/
β”œβ”€β”€ app/
β”‚ └── lib/
β”œβ”€β”€ authentication/
β”‚ └── lib/
β”‚ β”œβ”€β”€ authentication.dart
β”‚ └── src/
β”œβ”€β”€ user/
β”‚ └── lib/
β”‚ β”œβ”€β”€ user.dart
β”‚ └── src/
β”œβ”€β”€ products/
β”‚ └── lib/
β”‚ β”œβ”€β”€ products.dart
β”‚ └── src/
β”œβ”€β”€ payments/
β”‚ └── lib/
β”‚ β”œβ”€β”€ payments.dart
β”‚ └── src/
└── design_system/
└── lib/
β”œβ”€β”€ design_system.dart
└── src/

apps/
└── mobile/
└── lib/
└── main.dart

Characteristics​

  • Strong module boundaries
  • Features can become independent Dart/Flutter packages
  • Excellent for large teams
  • Useful for monorepos
  • More setup and tooling required

13. Monorepo Structure​

A full repository containing applications and shared packages.

project/
β”œβ”€β”€ apps/
β”‚ β”œβ”€β”€ mobile/
β”‚ β”‚ β”œβ”€β”€ android/
β”‚ β”‚ β”œβ”€β”€ ios/
β”‚ β”‚ └── lib/
β”‚ β”œβ”€β”€ web/
β”‚ └── admin/
β”œβ”€β”€ packages/
β”‚ β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ networking/
β”‚ β”œβ”€β”€ authentication/
β”‚ β”œβ”€β”€ database/
β”‚ β”œβ”€β”€ design_system/
β”‚ └── shared_models/
β”œβ”€β”€ tools/
β”œβ”€β”€ scripts/
β”œβ”€β”€ melos.yaml
└── pubspec.yaml

Characteristics​

  • Shared packages across multiple Flutter applications
  • Good for mobile + web + desktop + admin products
  • Suitable for large organizations
  • Often paired with a monorepo tool such as Melos

14. Design-System-Oriented Structure​

Useful when the application has a large reusable UI system.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ app/
β”‚ β”œβ”€β”€ app.dart
β”‚ β”œβ”€β”€ router.dart
β”‚ └── theme/
β”œβ”€β”€ design_system/
β”‚ β”œβ”€β”€ tokens/
β”‚ β”‚ β”œβ”€β”€ colors.dart
β”‚ β”‚ β”œβ”€β”€ spacing.dart
β”‚ β”‚ β”œβ”€β”€ typography.dart
β”‚ β”‚ └── radii.dart
β”‚ β”œβ”€β”€ components/
β”‚ β”‚ β”œβ”€β”€ buttons/
β”‚ β”‚ β”œβ”€β”€ cards/
β”‚ β”‚ β”œβ”€β”€ dialogs/
β”‚ β”‚ β”œβ”€β”€ inputs/
β”‚ β”‚ └── navigation/
β”‚ └── extensions/
β”œβ”€β”€ features/
β”‚ β”œβ”€β”€ home/
β”‚ β”œβ”€β”€ profile/
β”‚ └── settings/
└── core/

Characteristics​

  • Centralized visual language
  • Excellent for product families
  • Makes UI consistency easier
  • Particularly useful for large applications

15. Domain-Driven Design (DDD)​

Organizes the application around business domains and bounded contexts.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ shared/
β”‚ β”œβ”€β”€ kernel/
β”‚ β”œβ”€β”€ value_objects/
β”‚ └── exceptions/
β”œβ”€β”€ domains/
β”‚ β”œβ”€β”€ identity/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ β”œβ”€β”€ application/
β”‚ β”‚ β”œβ”€β”€ infrastructure/
β”‚ β”‚ └── presentation/
β”‚ β”œβ”€β”€ catalog/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ β”œβ”€β”€ application/
β”‚ β”‚ β”œβ”€β”€ infrastructure/
β”‚ β”‚ └── presentation/
β”‚ └── ordering/
β”‚ β”œβ”€β”€ domain/
β”‚ β”œβ”€β”€ application/
β”‚ β”œβ”€β”€ infrastructure/
β”‚ └── presentation/
└── app/
β”œβ”€β”€ routing/
└── dependency_injection/

Characteristics​

  • Models the business domain explicitly
  • Useful for complex business applications
  • Strong boundaries between domains
  • Usually unnecessary for small apps

16. Vertical Slice Architecture​

Each feature contains everything needed to implement a complete user-facing slice.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ networking/
β”‚ β”œβ”€β”€ database/
β”‚ └── routing/
β”œβ”€β”€ features/
β”‚ β”œβ”€β”€ login/
β”‚ β”‚ β”œβ”€β”€ login_page.dart
β”‚ β”‚ β”œβ”€β”€ login_controller.dart
β”‚ β”‚ β”œβ”€β”€ login_state.dart
β”‚ β”‚ β”œβ”€β”€ login_repository.dart
β”‚ β”‚ └── login_models.dart
β”‚ β”œβ”€β”€ register/
β”‚ β”‚ β”œβ”€β”€ register_page.dart
β”‚ β”‚ β”œβ”€β”€ register_controller.dart
β”‚ β”‚ β”œβ”€β”€ register_state.dart
β”‚ β”‚ └── register_repository.dart
β”‚ └── checkout/
β”‚ β”œβ”€β”€ checkout_page.dart
β”‚ β”œβ”€β”€ checkout_controller.dart
β”‚ β”œβ”€β”€ checkout_state.dart
β”‚ └── checkout_repository.dart
└── shared/
β”œβ”€β”€ widgets/
└── extensions/

Characteristics​

  • Feature code is highly localized
  • Reduces cross-project dependencies
  • Excellent for rapidly evolving applications
  • Similar in spirit to feature-first architecture, but slices can contain the complete flow rather than following strict global layers

17. Hybrid Architecture​

Combines several approaches.

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ app/
β”‚ β”œβ”€β”€ app.dart
β”‚ β”œβ”€β”€ router.dart
β”‚ β”œβ”€β”€ theme/
β”‚ └── dependency_injection.dart
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ constants/
β”‚ β”œβ”€β”€ errors/
β”‚ β”œβ”€β”€ network/
β”‚ β”œβ”€β”€ storage/
β”‚ β”œβ”€β”€ extensions/
β”‚ └── widgets/
β”œβ”€β”€ features/
β”‚ β”œβ”€β”€ auth/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ └── presentation/
β”‚ β”œβ”€β”€ news/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ └── presentation/
β”‚ └── settings/
β”‚ β”œβ”€β”€ data/
β”‚ β”œβ”€β”€ domain/
β”‚ └── presentation/
β”œβ”€β”€ shared/
β”‚ β”œβ”€β”€ models/
β”‚ β”œβ”€β”€ widgets/
β”‚ └── services/
└── generated/

Characteristics​

This is often the most practical approach:

  • Feature-first at the top level
  • Clean Architecture inside complex features
  • Shared infrastructure in core
  • Reusable application components in shared
  • App-wide configuration in app

Quick Comparison

StructureSmall AppMedium AppLarge AppComplexity
FlatExcellentPoorPoorVery Low
Layer-DrivenGoodGoodFairLow
Feature-DrivenGoodExcellentExcellentMedium
MVCGoodGoodFairLow
MVVMGoodExcellentGoodMedium
BLoC + FeaturesGoodExcellentExcellentMedium
Riverpod + FeaturesGoodExcellentExcellentMedium
Clean ArchitectureFairExcellentExcellentHigh
Feature + Clean ArchitectureFairExcellentExcellentHigh
Repository PatternGoodExcellentExcellentMedium
Vertical SliceGoodExcellentExcellentMedium
DDDPoorGoodExcellentVery High
Modular / PackagesPoorGoodExcellentHigh
MonorepoPoorGoodExcellentVery High
Design SystemFairExcellentExcellentMedium
HybridExcellentExcellentExcellentMedium–High

Recommended Choices

Small Utility / Prototype​

lib/
β”œβ”€β”€ main.dart
β”œβ”€β”€ screens/
β”œβ”€β”€ widgets/
β”œβ”€β”€ models/
└── services/

Use this when the project is small enough that architecture would otherwise become overhead.

Normal Production App​

lib/
β”œβ”€β”€ app/
β”œβ”€β”€ core/
β”œβ”€β”€ features/
└── shared/

Use Feature-Driven Architecture as the primary organization.

Large Production App​

lib/
β”œβ”€β”€ app/
β”œβ”€β”€ core/
β”œβ”€β”€ features/
β”‚ β”œβ”€β”€ feature_a/
β”‚ β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ domain/
β”‚ β”‚ └── presentation/
β”‚ └── feature_b/
β”‚ β”œβ”€β”€ data/
β”‚ β”œβ”€β”€ domain/
β”‚ └── presentation/
└── shared/

Use Feature-First + Clean Architecture.

Multiple Apps / Large Team​

apps/
β”œβ”€β”€ mobile/
β”œβ”€β”€ web/
└── admin/

packages/
β”œβ”€β”€ core/
β”œβ”€β”€ design_system/
β”œβ”€β”€ authentication/
β”œβ”€β”€ networking/
└── shared_models/

Use a Monorepo + Modular Packages + Feature-First Architecture.


A Useful Rule of Thumb

Instead of asking:

"Which architecture is the best?"

Ask:

"Where will this project become difficult to maintain?"

For most Flutter projects, a practical progression is:

Small
↓
Flat
↓
Feature-Driven
↓
Feature-Driven + State Management
↓
Feature-Driven + Clean Architecture
↓
Modular / Monorepo
Large

Do not introduce Clean Architecture, DDD, or a monorepo simply because they are popular. Add architectural complexity when the project's size, team structure, domain complexity, testing requirements, or number of applications actually justifies it.