safe_route
safe_route
is a simple and type-safe navigation helper for Flutter applications.
No more dynamic arguments
and runtime crashes — everything is strictly typed.
Why?
Default Flutter navigation with Navigator.pushNamed
requires Object? arguments
.
It’s flexible but unsafe:
Navigator.of(context).pushNamed('/user', arguments: 123); // ❌ runtime crash if page expects String
With safe_route
, both arguments and results are typed at compile-time.
Features
- ✅ Type-safe arguments and results
- ✅ Nested routes (
SafeNestedRoute
) - ✅ Strongly typed navigation helpers
- ✅ Clean, declarative API
- ✅ Simple integration with
MaterialApp
Installation
Add to pubspec.yaml
:
dependencies:
safe_route: ^<latest_version>
Quick Start
1. Define routes
final homeRoute = SafeRoute<Null, int>(
name: '/',
builder: (context, _) => const HomePage(),
);
final settingsRoute = SafeRoute<int, bool>(
name: '/settings',
builder: (context, arguments) => const SettingsPage(),
);
2. Register them in SafeRouter
final router = SafeRouter()
..registerAll([homeRoute, settingsRoute])
..defaultPath = homeRoute.fullPath;
MaterialApp(
initialRoute: router.defaultPath,
onGenerateRoute: router.onGenerateRoute,
);
3. Navigate safely
// Navigate without arguments
Navigator.of(context).pushRoute(homeRoute, null);
// Navigate with arguments
Navigator.of(context).pushRoute(userRoute, "Alex");
// Return a result
Navigator.of(context).popRoute(userRoute, true);
// Receive a result
final isDark = await Navigator.of(context).pushRoute(settingsRoute, null);
Navigation Methods
safe_route
provides a convenient extension AppRouteNavigation
on NavigatorState
with typed wrappers around standard navigation methods:
Flutter API method | safe_route method |
---|---|
pushNamed |
pushRoute |
maybePop |
maybePopRoute |
pop |
popRoute . |
popAndPushNamed |
popAndPushRoute |
pushNamedAndRemoveUntil |
pushRouteAndRemoveUntil |
pushReplacementNamed |
pushReplacementRoute |
restorablePushNamed |
restorablePushRoute |
restorablePopAndPushNamed |
restorablePopAndPushRoute |
restorablePushNamedAndRemoveUntil |
restorablePushRouteAndRemoveUntil |
restorablePushReplacementNamed |
restorablePushReplacementRoute |
All methods ensure arguments and results are strictly typed.
Full Example
class AppRouter {
AppRouter() : safeRouter = SafeRouter() {
safeRouter
..registerAll([
loginRoute,
homeRoute,
settingsRoute,
])
..defaultPath = homeRoute.fullPath;
}
final SafeRouter safeRouter;
final loginRoute = SafeRoute<Null, String>(
name: '/',
builder: (context, __) => const LoginPage(),
);
final homeRoute = SafeRoute<String, void>(
name: '/home',
builder: (context, username) => HomePage(username: username),
);
final settingsRoute = SafeRoute<Null, bool>(
name: '/settings',
builder: (context, __) => const SettingsPage(),
);
}
final AppRouter router = AppRouter();
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: router.safeRouter.defaultPath,
onGenerateRoute: router.safeRouter.onGenerateRoute,
);
}
}