zenrouter 0.4.5 copy "zenrouter: ^0.4.5" to clipboard
zenrouter: ^0.4.5 copied to clipboard

A powerful Flutter router with deep linking, web support, type-safe routing, guards, redirects, and zero boilerplate.

Logo

ZenRouter ๐Ÿง˜ #

The Ultimate Flutter Router for Every Navigation Pattern

pub package Test Codecov - zenrouter

ZenRouter is the only router you'll ever need - supporting three distinct paradigms to handle any routing scenario. From simple mobile apps to complex web applications with deep linking, ZenRouter adapts to your needs.


Why ZenRouter? #

One router. Three paradigms. Infinite possibilities.

โœจ Three Paradigms in One - Choose imperative, declarative, or coordinator based on your needs
๐Ÿš€ Start Simple, Scale Seamlessly - Begin with basics, add complexity as you grow
๐ŸŒ Full Web & Deep Linking - Built-in URL handling and browser navigation
โšก Blazing Fast - Efficient Myers diff algorithm for optimal performance
๐Ÿ”’ Type-Safe - Catch routing errors at compile-time, not runtime
๐Ÿ›ก๏ธ Powerful Guards & Redirects - Protect routes and control navigation flow
๐Ÿ“ฆ Zero Boilerplate - Clean, mixin-based architecture
๐Ÿ“ No Codegen Needed (for core) - Pure Dart, no build_runner or generated files required. (Optional file-based routing via zenrouter_file_generator is available when you want codegen.)


Three Paradigms, Infinite Flexibility #

Choose Your Path #

Need web support, deep linking, and router devtools to handle complex scalable navigation?
โ”‚
โ”œโ”€ YES โ†’ Use Coordinator
โ”‚        โœ“ Deep linking & URL sync
โ”‚        โœ“ Devtools ready!
โ”‚        โœ“ Back button gesture (Web back, predictive back, etc)
โ”‚        โœ“ Perfect for web, complex mobile apps
โ”‚
โ””โ”€ NO โ†’ Is navigation driven by state?
       โ”‚
       โ”œโ”€ YES โ†’ Use Declarative
       โ”‚        โœ“ Efficient Myers diff
       โ”‚        โœ“ React-like patterns
       โ”‚        โœ“ Perfect for tab bars
       โ”‚
       โ””โ”€ NO โ†’ Use Imperative
                โœ“ Simple & direct
                โœ“ Full control
                โœ“ Perfect for mobile

๐ŸŽฎ Imperative - Direct Control #

Perfect for mobile apps and event-driven navigation

Quick Start

First, define a navigation path and all possible routes. For example, let's say you have Home and Profile routes:

class Home extends RouteTarget {}

class Profile extends RouteTarget {
  Profile(this.id);
  final String id;

  /// Make sure to add `id` in `props` to prevent unwanted behavior when pushing the same route
  List<Object?> get props => [id];
}

final appPath = NavigationPath.create();

Now that the setup is complete, let's wire up the navigation. The NavigationStack widget expects two main parameters:

  • path: The route stack to display
  • resolver: A function for resolving which transition type each route will use
class AppRouter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return NavigationStack(
      path: appPath,
      resolver: (route) => switch (route) {
        Home() => StackTransition.material(HomePage()),
        Profile() => StackTransition.material(ProfilePage()),
      },
    );
  }
}

That's it! You've successfully set up imperative routing for your app. To navigate, simply call push() to open a new route (you can await the result when it's popped), and pop() to go back. The NavigationPath class offers many handy operationsโ€”see more in the NavigationPath API documentation.

// Open Profile route
ElevatedButton(
  onPressed: () => appPath.push(Profile('Joe')),
  child: Text('Open "Joe" profile'),
),

// Pop back
appPath.pop();

When to use:

  • Mobile-only applications
  • Button clicks and gesture-driven navigation
  • Migrating from Navigator 1.0
  • You want simple, direct control

โ†’ Learn Imperative Routing


๐Ÿ“Š Declarative - State-Driven #

Perfect for tab bars, filtered lists, and React-like UIs

Quick Start

In declarative navigation, your UI is a function of your state. When your state changes, the navigation stack automatically updates to reflect it. ZenRouter uses the Myers diff algorithm to efficiently compute the minimal changes needed, ensuring optimal performance even with complex navigation stacks.

Let's build a simple tab navigation example. First, define your routes and state:

class HomeTab extends RouteTarget {}
class SearchTab extends RouteTarget {}
class ProfileTab extends RouteTarget {}

class TabNavigator extends StatefulWidget {
  @override
  State<TabNavigator> createState() => _TabNavigatorState();
}

class _TabNavigatorState extends State<TabNavigator> {
  int currentTab = 0;
  
  @override
  Widget build(BuildContext context) {
    return NavigationStack.declarative(
      routes: [
        HomeTab(),
        switch (currentTab) {
          0 => SearchTab(),
          1 => ProfileTab(),
          _ => SearchTab(),
        },
      ],
      resolver: (route) => switch (route) {
        HomeTab() => StackTransition.material(HomePage()),
        SearchTab() => StackTransition.material(SearchPage()),
        ProfileTab() => StackTransition.material(ProfilePage()),
      },
    );
  }
}

When you update the state, the navigation stack automatically reflects the changes. ZenRouter intelligently diffs the old and new route lists to determine the minimal set of push/pop operations needed:

// Switch tabs
setState(() => currentTab = 1); // Automatically pushes ProfileTab

That's it! The navigation stack stays perfectly in sync with your stateโ€”no manual push() or pop() calls needed. This pattern is ideal for tab bars, filtered lists, or any UI where navigation is derived from application state.

When to use:

  • Tab navigation
  • Filtered or dynamic lists
  • State-driven UIs
  • React-like declarative patterns

โ†’ Learn Declarative Routing


๐Ÿ—บ๏ธ Coordinator - Deep Linking & Web #

Perfect for web apps and complex navigation hierarchies

Quick Start

Ready to level up? When your app needs to support deep linking, web URLs, or browser navigation, it's time to graduate to the Coordinator pattern. This is the final and most powerful routing paradigm in ZenRouterโ€”built for production apps that need to handle complex navigation scenarios across multiple platforms.

The Coordinator pattern gives you:

  • ๐Ÿ”— Deep linking - Open specific screens from external sources (myapp://profile/123)
  • ๐ŸŒ URL synchronization - Keep browser URLs in sync with navigation state
  • โฌ…๏ธ Browser back button - Native web navigation that just works
  • ๐Ÿ› ๏ธ Dev tools - Built-in debugging and route inspection

Let's build a Coordinator-powered app. First, define your routes with URI support:

First, create a base route class for your app. The RouteUnique mixin is required for Coordinatorโ€”it enforces that every route must define a unique URI, which is essential for deep linking and URL synchronization:

abstract class AppRoute extends RouteTarget with RouteUnique {}

Now define your concrete routes by extending AppRoute:

class HomeRoute extends AppRoute {
  @override
  Uri toUri() => Uri.parse('/');
  
  @override
  Widget build(AppCoordinator coordinator, BuildContext context) {
    return HomePage(coordinator: coordinator);
  }
}

class ProfileRoute extends AppRoute {
  ProfileRoute(this.userId);
  final String userId;

  @override
  List<Object?> get props => [userId];
  
  @override
  Uri toUri() => Uri.parse('/profile/$userId');
  
  @override
  Widget build(AppCoordinator coordinator, BuildContext context) {
    return ProfilePage(userId: userId, coordinator: coordinator);
  }
}

Important

Notice that the build() method uses AppCoordinator (not Coordinator) as the parameter type. This is because Coordinator is covariantโ€”when you create your AppCoordinator extends Coordinator<AppRoute>, all your routes will receive that specific coordinator type, giving you type-safe access to any custom methods or properties you add to AppCoordinator.

Next, create your Coordinator by extending the Coordinator class and implementing URI parsing:

class AppCoordinator extends Coordinator<RouteTarget> {
  @override
  RouteTarget parseRouteFromUri(Uri uri) {
    return switch (uri.pathSegments) {
      [] => HomeRoute(),
      ['profile', String userId] => ProfileRoute(userId),
      _ => NotFoundRoute(),
    };
  }
}

Finally, wire it up with MaterialApp.router to enable full platform navigation:

class MyApp extends StatelessWidget {
  final coordinator = AppCoordinator();
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: coordinator.routerDelegate,
      routeInformationParser: coordinator.routeInformationParser,
    );
  }
}

That's it! Your app now supports:

  • โœ… Deep links: myapp://profile/joe automatically navigates to Joe's profile
  • โœ… Web URLs: Users can bookmark and share https://myapp.com/profile/joe
  • โœ… Browser navigation: Back/forward buttons work seamlessly
  • โœ… Dev tools: Debug routes and navigation flows in real-time

The Coordinator handles all the complexity of URI parsing, route restoration, and platform integrationโ€”you just focus on building your app.

When to use:

  • Web applications
  • Deep linking requirements
  • Complex nested navigation
  • URL synchronization needed

โ†’ Learn Coordinator Pattern


Quick Comparison #

Imperative Declarative Coordinator
Simplicity โญโญโญ โญโญ โญ
Web Support โŒ โŒ โœ…
Deep Linking โŒ โŒ โœ…
State-Driven Compatible โœ… Native Compatible
Best For Mobile apps Tab bars, lists Web, large apps
Route Ability Guard, Redirect, Transition Guard, Redirect, Transition Guard, Redirect, Transition, DeepLink

Documentation #

๐Ÿ“š Guides #

๐Ÿ”ง API Reference #

๐Ÿ’ก Examples #

To get Next.js / Nuxt.jsโ€“style file-based routing on top of the Coordinator paradigm, use the optional zenrouter_file_generator package, which provides annotations and a build_runner-based code generator.


Contributing #

We welcome contributions! See CONTRIBUTING.md for guidelines.

License #

Apache 2.0 License - see LICENSE for details.

Created With Love By #

definev


The Ultimate Router for Flutter

Documentation โ€ข Examples โ€ข Issues

Happy Routing! ๐Ÿง˜

65
likes
0
points
979
downloads

Publisher

verified publisherzennn.dev

Weekly Downloads

A powerful Flutter router with deep linking, web support, type-safe routing, guards, redirects, and zero boilerplate.

Homepage
Repository (GitHub)
View/report issues

Topics

#router #navigation #routing #deep-linking #web

Documentation

Documentation

License

unknown (license)

Dependencies

collection, flutter

More

Packages that depend on zenrouter