Flutter Integration
The nest_flutter package provides seamless integration between Nest Dart’s modular architecture and Flutter applications, with built-in support for GoRouter navigation.
Installation
Add the dependency to your pubspec.yaml:
dependencies :
nest_flutter : ^latest
Quick Start
Create Your Module
Define a module with your services and routes: import 'package:nest_flutter/nest_flutter.dart' ;
class TodoModule extends Module {
@override
List < Module > get imports => [ CoreModule ()];
@override
Future < void > providers ( Locator locator) async {
locator. registerSingleton < TodoService >(
JsonPlaceholderTodoService (client : locator. get < Client >()),
);
locator. registerSingleton < TodoProvider >(
TodoProvider (locator. get < TodoService >(), locator. get < ConfigPreference >()),
);
}
@override
List < Type > get exports => [ TodoService , TodoProvider ];
@override
String ? get routePrefix => '/todos' ;
@override
List < RouteBase > get routes => [
GoRoute (path : '/' , builder : (context, state) => const TodoListView ()),
GoRoute (
path : '/:id' ,
builder : (context, state) => TodoDetailView (
todoId : int . tryParse (state.pathParameters[ 'id' ] ?? '0' ) ?? 0 ,
),
),
];
}
Create App Module
Create a root module that imports all feature modules: class AppModule extends Module {
@override
List < Module > get imports => [
SplashModule (),
TodoModule (),
];
@override
Future < void > providers ( Locator _) async {}
}
Wrap Your App with ModularApp
Initialize the module system in your main function: import 'package:flutter/material.dart' ;
import 'package:nest_flutter/nest_flutter.dart' ;
void main () {
WidgetsFlutterBinding . ensureInitialized ();
runApp ( ModularApp (module : AppModule (), child : const MainApp ()));
}
class MainApp extends StatelessWidget {
const MainApp ({ super .key});
@override
Widget build ( BuildContext context) {
return MaterialApp . router (
routerConfig : Modular . router ((router) {
return GoRouter (
routes : router.configuration.routes,
initialLocation : '/todos' ,
debugLogDiagnostics : true ,
);
}),
);
}
}
The ModularApp widget is the entry point for Nest Flutter integration. It initializes the dependency injection container and makes services available throughout your app.
Properties
module (required): The root module of your application
child (required): Your app widget
container: Optional custom ApplicationContainer instance
loading: Optional loading widget shown during initialization
The ModularApp widget automatically handles async module initialization. All services registered in providers() methods are available after initialization completes.
Accessing Dependencies
Nest Flutter provides multiple ways to access your services:
Using Modular.get()
Access services from anywhere in your widget tree:
import 'package:nest_flutter/nest_flutter.dart' ;
class MainApp extends StatelessWidget {
@override
Widget build ( BuildContext context) {
return ChangeNotifierProvider (
create : (context) => Modular . get < TodoProvider >(),
child : MaterialApp . router (
routerConfig : Modular . router ((router) => router),
),
);
}
}
Using Modular.of(context)
Access the container through the widget context:
final container = Modular . of (context);
final service = container. get < MyService >();
Available Methods
Get Service
Get with Instance Name
Get Async Service
Get with Parameters
Check if Registered
Get Available Services
final service = Modular . get < UserService >();
Module-Based Routing
Nest Flutter extends the base Module class with the RouteMixin to support GoRouter integration.
RouteMixin
Add routes directly to your modules:
class TodoModule extends Module {
@override
String ? get routePrefix => '/todos' ;
@override
List < RouteBase > get routes => [
GoRoute (
path : '/' ,
builder : (context, state) => const TodoListView (),
),
GoRoute (
path : '/:id' ,
builder : (context, state) => TodoDetailView (
todoId : int . tryParse (state.pathParameters[ 'id' ] ?? '0' ) ?? 0 ,
),
),
];
}
Routes are automatically prefixed with the module’s routePrefix. In the example above, the routes become /todos/ and /todos/:id.
Nested Routes
Create hierarchical route structures:
class ModuleB extends Module {
@override
String ? get routePrefix => '/module-b' ;
@override
List < RouteBase > get routes => [
GoRoute (
path : '/' ,
builder : (context, state) => const ModuleBHome (),
routes : [
GoRoute (
path : 'second' ,
builder : (context, state) => const ModuleBSecond (),
),
],
),
];
}
This creates:
/module-b/ - Main page
/module-b/second - Nested page
Router Configuration
Customize the GoRouter instance:
MaterialApp . router (
routerConfig : Modular . router ((router) {
return GoRouter (
routes : router.configuration.routes,
initialLocation : '/todos' ,
debugLogDiagnostics : true ,
redirect : (context, state) {
// Custom redirect logic
return null ;
},
errorBuilder : (context, state) {
return ErrorPage (error : state.error);
},
);
}),
)
The router is cached to prevent recreation during hot reloads. Use Modular.clearRouterCache() if you need to force router recreation.
Router Cache Management
// Clear the cached router
Modular . clearRouterCache ();
// Check if router is cached
if ( Modular .isRouterCached) {
print ( 'Router is cached' );
}
// Get cached router instance
final cachedRouter = Modular .cachedRouter;
Navigation
Use standard GoRouter navigation methods:
import 'package:go_router/go_router.dart' ;
// Navigate to a route
context. push ( '/todos/1' );
// Navigate and replace
context. pushReplacement ( '/todos' );
// Go to a route (removes all previous routes)
context. go ( '/todos' );
// Navigate back
context. pop ();
Complete Example
Here’s a complete example with modules, routes, and dependency injection:
main.dart
core_module.dart
todo_module.dart
import 'package:flutter/material.dart' ;
import 'package:nest_flutter/nest_flutter.dart' ;
import 'package:provider/provider.dart' ;
void main () {
WidgetsFlutterBinding . ensureInitialized ();
runApp ( ModularApp (module : AppModule (), child : const MainApp ()));
}
class AppModule extends Module {
@override
List < Module > get imports => [
SplashModule (),
TodoModule (),
];
@override
Future < void > providers ( Locator _) async {}
}
class MainApp extends StatelessWidget {
const MainApp ({ super .key});
@override
Widget build ( BuildContext context) {
return ChangeNotifierProvider (
create : (context) => Modular . get < TodoProvider >(),
child : MaterialApp . router (
routerConfig : Modular . router ((router) {
return GoRouter (
routes : router.configuration.routes,
initialLocation : '/todos' ,
debugLogDiagnostics : true ,
);
}),
),
);
}
}
Best Practices
Keep modules focused on specific features or domains
Use exports to control which services are accessible to other modules
Leverage routePrefix to organize routes hierarchically
Use the loading property of ModularApp for custom loading UI
Cache router to prevent recreation on hot reload
See Also