Routes & Modules
Routes & Modules

Routes & Modules

Modules are the building blocks of a GoRouter Modular app. Each module encapsulates its own routes, dependencies, and business logic.

Module Structure

class ProductsModule extends Module {
  @override
  FutureBinds binds(Injector i) {
    i.addSingleton<ProductsController>((i) => ProductsController());
  }
 
  @override
  List<ModularRoute> get routes => [
    ChildRoute('/', child: (_, __) => ProductsPage()),
    ChildRoute('/details/:id', child: (_, state) =>
      ProductDetailPage(id: state.pathParameters['id']!)),
  ];
}

Route Types

ChildRoute

Defines a single page within a module:

ChildRoute('/', child: (context, state) => HomePage())
ChildRoute('/profile', child: (context, state) => ProfilePage())
ChildRoute('/user/:id', child: (context, state) =>
  UserPage(id: state.pathParameters['id']!))

ModuleRoute

Delegates a path to a separate module:

ModuleRoute('/products', module: ProductsModule())
ModuleRoute('/auth', module: AuthModule())

ShellModularRoute

Wraps child routes with a shared layout (e.g. a navigation rail). All children share the same navigator:

ShellModularRoute(
  builder: (context, state, child) => MainLayout(child: child),
  routes: [
    ModuleRoute('/home', module: HomeModule()),
    ModuleRoute('/settings', module: SettingsModule()),
  ],
)

StatefulShellModularRoute

For bottom navigation bars and tabs that preserve state across branches. Each branch gets its own navigator backed by an IndexedStack:

StatefulShellModularRoute(
  builder: (context, state, navigationShell) => AppShell(
    navigationShell: navigationShell,
  ),
  branches: [
    ModularBranch(module: HomeModule()),
    ModularBranch(module: SearchModule()),
    ModularBranch(routes: [
      ChildRoute('/profile', child: (_, __) => ProfilePage()),
    ]),
  ],
)

See Shell Routes for detailed documentation.

Module Nesting

Modules can contain other modules for hierarchical navigation:

class ShopModule extends Module {
  @override
  List<ModularRoute> get routes => [
    ChildRoute('/', child: (_, __) => ShopHomePage()),
    ModuleRoute('/products', module: ProductsModule()),
    ModuleRoute('/cart', module: CartModule()),
  ];
}

The resulting paths are:

  • /shop — ShopHomePage
  • /shop/products — ProductsModule entry point
  • /shop/cart — CartModule entry point

Route Parameters

// Path parameters
ChildRoute('/user/:id', child: (_, state) =>
  UserPage(id: state.pathParameters['id']!))
 
// Navigate
context.go('/user/123');

Page Transitions

Attach transitions at the module or route level:

ModuleRoute('/home', module: HomeModule(),
  transition: GoTransitions.fadeUpwards,
  duration: Duration(milliseconds: 300))

See Page Transitions for all available transitions.

Common Patterns

Feature Module

class AuthModule extends Module {
  @override
  FutureBinds binds(Injector i) {
    i.addSingleton<AuthController>((i) => AuthController());
  }
 
  @override
  List<ModularRoute> get routes => [
    ChildRoute('/login', child: (_, __) => LoginPage()),
    ChildRoute('/register', child: (_, __) => RegisterPage()),
    ChildRoute('/forgot-password', child: (_, __) => ForgotPasswordPage()),
  ];
}

App Module

class AppModule extends Module {
  @override
  FutureBinds binds(Injector i) {
    i.addSingleton<AppConfig>((i) => AppConfig());
  }
 
  @override
  List<ModularRoute> get routes => [
    ModuleRoute('/', module: HomeModule()),
    ModuleRoute('/products', module: ProductsModule()),
    ModuleRoute('/auth', module: AuthModule()),
    ModuleRoute('/settings', module: SettingsModule()),
  ];
}

Best Practices

  1. One module per feature — Keep related routes and dependencies together.
  2. Use ModuleRoute for features — Isolate each feature in its own module.
  3. Use ChildRoute for pages — Individual pages within a module.
  4. Keep modules small — Easier to maintain and test.
  5. Plan your route hierarchy — Think about your app's navigation flow before coding.