navigation-and-routing

Configures a single go_router setup with guards, shells, and deep links in Flutter apps.

Updated Aug 22, 2026
One-click install
npx skills add https://github.com/zakariaf/NearlyStop --skill navigation-and-routing-zakariaf
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: navigation-and-routing
Source: https://github.com/zakariaf/NearlyStop/tree/main/.claude/skills/navigation-and-routing
Command: npx skills add https://github.com/zakariaf/NearlyStop --skill navigation-and-routing-zakariaf

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes scripts (resource) and references (resource) components.

What problem does it solve? Flutter apps often accumulate fragmented navigation: multiple routers, identity smuggled through state.extra that breaks on cold-start deep links, imperative Navigator calls mixed with go_router, and redirect guards that loop forever. This Skill enforces one declarative GoRouter with URL-addressable screens, pure redirect guards, and correct back-button behavior. ## Core Features & Use Cases - Single Router Architecture: Enforces exactly one GoRouter in lib/routing/ wired via MaterialApp.router, with a static check script that fails PRs violating the rules. - Deep-Link-Safe Identity: Requires screen identity in path parameters so cold starts, process death, and notification taps rebuild the correct screen from the URL alone. - Pure Redirect Guards: Implements auth and onboarding gates as pure, loop-free redirect functions re-evaluated reactively through a Riverpod refreshListenable. - Use Case: When adding a bottom-navigation shell to a Flutter app, use StatefulShellRoute.indexedStack so each tab keeps its own navigation stack, and map notification payloads to locations through a pure function. ## Quick Start Ask the AI to add a new deep-linkable detail screen route with an auth guard to the Flutter app using the navigation-and-routing conventions.

Frequently Asked Questions about navigation-and-routing

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I set up go_router in a Flutter app?

Construct exactly one GoRouter in a routing directory, expose it through a Riverpod provider, and hand it to a single MaterialApp.router in app.dart. Define routes as a declarative tree of GoRoutes with typed path constants rather than hand-concatenated strings.

What is the difference between context.go and context.push in go_router?

context.go replaces the navigation stack and suits tab roots or post-login destinations, while context.push stacks a page you expect to pop back from, such as a detail or edit screen. Mixing them incorrectly breaks the system back button.

How do I implement auth guards with go_router redirect?

Write a pure redirect function that takes an auth state snapshot and GoRouterState and returns a location string or null. Bridge your auth provider to a refreshListenable so the router re-evaluates guards when auth changes, and always allow the guard's own target to avoid redirect loops.

Why is state.extra null after a deep link or app restart?

state.extra holds a live in-memory Dart object that is not serialized, so it is null on cold-start deep links and after process death or state restoration. Put screen identity in path parameters so the URL alone fully reconstructs the screen, and treat extra only as an optional preloaded-object optimization.

How do I keep tab state when switching bottom navigation tabs in Flutter?

Use StatefulShellRoute.indexedStack, which keeps each branch's navigation stack alive in an IndexedStack across tab switches. Switch branches with navigationShell.goBranch, passing initialLocation when re-tapping the active tab to return it to its root.

How do I intercept the back button for unsaved changes in Flutter?

Use PopScope with canPop set to false while the form is dirty, then handle onPopInvokedWithResult to show a confirmation dialog and only pop after the user confirms. WillPopScope is removed, and you must guard any post-await context use with context.mounted.