0
0
FlutterComparisonBeginner · 4 min read

Named Routes vs go_router Flutter: Key Differences and Usage

Flutter's named routes provide a simple, built-in way to navigate using string route names, suitable for small apps. The go_router package offers a more powerful, declarative, and flexible routing system with deep linking and nested routes, ideal for larger or complex apps.
⚖️

Quick Comparison

This table summarizes key factors comparing Flutter's built-in named routes and the go_router package.

FactorNamed Routesgo_router
Setup ComplexitySimple to set up with MaterialAppRequires adding go_router package and setup
Routing StyleImperative with string route namesDeclarative with typed routes and URL patterns
Deep LinkingLimited support, manual handlingBuilt-in deep linking support
Nested RoutesNo native support, manual workaroundsNative nested routing support
Route ParametersPassed via arguments, less type-safeTyped parameters in route paths
Navigation GuardsNo built-in guardsSupports redirect and guard logic
ScalabilityBest for small/simple appsDesigned for medium to large apps
⚖️

Key Differences

Named routes in Flutter use a simple map of string route names to widget builders inside MaterialApp. Navigation happens by calling Navigator.pushNamed with a route name. This approach is straightforward but can become hard to manage as the app grows, especially with complex navigation flows or deep linking.

On the other hand, go_router is a third-party package that provides a declarative routing API. It uses URL-like route patterns, supports nested routes, and allows passing typed parameters directly in the route path. It also has built-in support for deep linking and navigation guards, making it easier to handle authentication flows or conditional redirects.

While named routes are part of Flutter's core and require no extra dependencies, go_router requires adding a package but offers more features and better scalability for complex apps.

⚖️

Named Routes Code Comparison

This example shows how to define and navigate using Flutter's built-in named routes.

dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',
      routes: {
        '/': (context) => HomeScreen(),
        '/details': (context) => DetailsScreen(),
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Navigator.pushNamed(context, '/details'),
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Details')),
      body: Center(child: Text('Details Screen')),
    );
  }
}
Output
App with a Home screen showing a button labeled 'Go to Details'. Pressing it navigates to a Details screen with the text 'Details Screen'.
↔️

go_router Equivalent

This example shows the same navigation using the go_router package with declarative routes.

dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  final GoRouter router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => HomeScreen(),
      ),
      GoRoute(
        path: '/details',
        builder: (context, state) => DetailsScreen(),
      ),
    ],
  );

  runApp(MyApp(router: router));
}

class MyApp extends StatelessWidget {
  final GoRouter router;
  MyApp({required this.router});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: router,
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => context.go('/details'),
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Details')),
      body: Center(child: Text('Details Screen')),
    );
  }
}
Output
App with a Home screen showing a button labeled 'Go to Details'. Pressing it navigates to a Details screen with the text 'Details Screen'.
🎯

When to Use Which

Choose named routes when building small or simple Flutter apps that need quick and easy navigation without extra dependencies. They are straightforward and good for apps with limited screens and simple flows.

Choose go_router when your app requires complex navigation, such as nested routes, deep linking, route parameters, or navigation guards. It is better suited for medium to large apps where maintainability and scalability are important.

Key Takeaways

Named routes are simple and built-in, ideal for small apps with basic navigation.
go_router offers declarative, flexible routing with deep linking and nested routes.
Use go_router for complex apps needing scalable and maintainable navigation.
Named routes require less setup but lack advanced features like navigation guards.
go_router improves type safety and URL-based navigation patterns.