What Is LEGO Architecture?
LEGO Architecture is a philosophy that treats code like interlocking bricks. Each brick performs one focused task and can be assembled into larger structures through well‑defined contracts, rather than through tight coupling of concrete implementations.
Core Principles
- Single Responsibility: Every component should have one clear purpose.
- Contract‑Based Interaction: Use abstract classes, interfaces, or function signatures to connect components.
- Encapsulation: Hide internal details; expose only what is necessary for other bricks.
- Feature‑Centric Structure: Organize files by feature, not by type, to keep related logic together.
Applying LEGO Architecture in Flutter
Widget Bricks
Instead of monolithic widgets that handle data loading, rendering, and state management, break them into small, reusable bricks:
SurfaceCard– a generic card wrapper.ProductThumbnail– displays the product image.PriceTag– shows the price.
These bricks can be combined in ProductCard or reused in other parts of the app, reducing duplication.
Contracts Over Concrete Dependencies
For a feature like adding to cart, define an abstraction:
abstract class CartWriter {
Future add(String productId);
}
Concrete implementations such as ApiCartWriter and InMemoryCartWriter satisfy this contract. The UI widget receives a CartWriter through constructor injection:
class AddToCartButton extends StatelessWidget {
final CartWriter cartWriter;
AddToCartButton({required this.cartWriter});
// ...
}
This design allows testing with a lightweight writer and swapping implementations without touching the widget.
Feature‑Based Folder Structure
lib/
features/
product/
product.dart // Barrel file
src/
widgets/
services/
models/
cart/
cart.dart
src/
widgets/
services/
core/
contracts/
di/
The barrel file exports only the public API, keeping internal files private.
Service Locator with GetIt
final getIt = GetIt.instance;
void setupServiceLocator() {
getIt.registerLazySingleton(() => ProductRepository());
}
All features register dependencies through contracts, and the locator resolves them at runtime.
Feature Modules
abstract class FeatureModule {
List get routes;
void registerDependencies();
}
Modules expose routes and register their own dependencies, enabling the app shell to assemble modules without modifying core code.
LEGO vs. Clean Architecture
| LEGO Architecture | Clean Architecture |
|---|---|
| Mindset focused on modular bricks | Layered structure with strict boundaries |
| Flexible brick size: widgets, services, features | Fixed layers: Domain, Data, Presentation |
| Easy to start, less boilerplate | Strong testability, more boilerplate |
| Great for small to medium projects | Ideal for large, long‑term enterprise apps |
Helpful Tools and Packages
- lego_cli – CLI for generating modular widgets and snippets.
- get_it – Service locator for dependency injection.
- go_router – Modular routing.
- Melos – Monorepo management for multi‑package projects.
Common Pitfalls and Best Practices
- Fake modularity: Splitting code only for the sake of splitting leads to complexity. Focus on logical separation.
- Excessive abstraction: Too many contracts can obscure intent. Keep abstractions purposeful.
- Neglecting tests: Contracts enable unit tests. Write tests for each brick independently.
- Ignoring performance: Small widgets can increase rebuild overhead. Use
constwhere possible.
Conclusion
LEGO Architecture transforms a Flutter codebase into a collection of reusable, contract‑driven bricks. By emphasizing single responsibility, encapsulation, and feature‑centric organization, developers can build scalable apps that are easy to maintain, test, and extend. Leveraging tools like get_it, go_router, and lego_cli further streamlines the process, making modular development approachable for teams of all sizes.

Leave a Reply