Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/khode-io/nest-dart/llms.txt

Use this file to discover all available pages before exploring further.

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

1

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,
      ),
    ),
  ];
}
2

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 {}
}
3

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,
        );
      }),
    );
  }
}

ModularApp Widget

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

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;
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:
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

Build docs developers (and LLMs) love