Learn

Modules, tabs, and nested navigation

Let features own routes while each application chooses placement, Navigator scopes, and retained tab stacks.

v1.1.0Intermediate

Modules, tabs, and nested navigation

A Module answers “which routes belong to this feature?” A Mount answers “where does this application place that feature?” A Scope owns one Navigator stack.

A feature exports a Module

dart
NavigationModule createCatalogModule() => NavigationModule(
  id: const NavigationModuleId('catalog'),
  routes: <NavigationRouteDefinitionBase>[
    catalogRoute,
    productRoute,
  ],
);

The feature does not know whether it appears at /catalog, /shop, in one app, or in two shells.

The app mounts it

dart
NavigationMount(
  id: const NavigationMountId('customer-catalog'),
  moduleId: const NavigationModuleId('catalog'),
  scopeId: const NavigationScopeId('catalog-tab'),
  pathPrefix: '/catalog',
)

Each tab gets its own Scope

dart
scopes: const <NavigationScopeDefinition>[
  NavigationScopeDefinition(id: NavigationScopeId('root')),
  NavigationScopeDefinition(
    id: NavigationScopeId('shell'),
    parentId: NavigationScopeId('root'),
  ),
  NavigationScopeDefinition(
    id: NavigationScopeId('catalog-tab'),
    parentId: NavigationScopeId('shell'),
  ),
  NavigationScopeDefinition(
    id: NavigationScopeId('profile-tab'),
    parentId: NavigationScopeId('shell'),
  ),
],

Render the selected child stack:

dart
const NavigationActiveOutlet(parentScopeId: NavigationScopeId('shell'))

Switch tabs without destroying either stack:

dart
navigation.activateBranch(const NavigationScopeId('profile-tab'));

If Catalog contains [Catalog, Product], switching to Profile and back restores that exact Catalog stack. Use resetBranch only when you intentionally want to clear it, for example after sign-out.

The complete NavigationBar application is built in Tutorials → Modular tabs.