DEV Community

GeekyAnts Inc
GeekyAnts Inc

Posted on • Originally published at geekyants.com

Advanced Navigation in Flutter Web: A Deep Dive with go_router published: false

Advanced Navigation in Flutter Web: A Deep Dive with go_router

When building multi-screen apps for the web, navigation in Flutter can become complex surprisingly fast. Once browser URLs, deep links, authentication redirects, and shared layouts enter the picture, the traditional navigation approach can start to feel hard to scale.

That is where go_router becomes especially useful.

Backed by the Flutter team, go_router provides a declarative way to manage routes across Flutter apps while also fitting the expectations of web navigation. It helps with:

  • Declarative route definitions
  • Built-in redirection support
  • Deep linking
  • URL synchronization
  • Cross-platform navigation patterns for mobile, web, and desktop

As your application grows in size and complexity, go_router makes routing logic more predictable and easier to maintain.

In this article, we will go beyond the basics and look at practical patterns for building advanced navigation flows in Flutter Web, including:

  • Shared layouts with app bars and bottom navigation
  • Authentication redirects
  • Preserving intended URLs
  • Path and query parameters
  • Syncing UI state with the browser URL
  • Passing complex data with state.extra
  • Common pitfalls and workarounds

Why go_router works well for Flutter Web

Flutter Web users expect a browser-like experience:

  • Meaningful URLs
  • Back and forward button support
  • Shareable routes
  • Refresh-safe navigation
  • Deep linking into specific screens

If your routing layer does not align with those expectations, the app can feel clunky even if the UI looks polished.

go_router bridges that gap by bringing Flutter’s declarative style into a navigation model that feels natural on the web.


Handling navigation with a persistent AppBar and BottomNavigationBar

Let’s look at a very common use case.

Suppose you are building a Flutter Web app with:

  • a persistent AppBar
  • a BottomNavigationBar
  • multiple screens like Home, Search, and Settings

When the user switches tabs, you usually want only the main content area to update. The top and bottom navigation chrome should remain stable.

The problem without a shared shell

If each route defines its own Scaffold, AppBar, and BottomNavigationBar, a few issues appear:

  • Flutter rebuilds the whole page when switching routes
  • Shared UI elements flash or reset
  • Scaffold code gets duplicated across screens
  • Restoring a route directly from a URL becomes harder to manage cleanly

On the web, this often feels like the entire page is reloading instead of just swapping content.

The better approach: ShellRoute

ShellRoute gives you a persistent wrapper layout.

You define a parent shell that contains the shared structure, and the child routes are rendered inside that shell. This means:

  • the shared layout stays intact
  • only the inner content changes
  • state is preserved more reliably
  • your route structure stays cleaner

Example route setup with ShellRoute


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

final GoRouter router = GoRouter(
  routes: [
    ShellRoute(
      builder: (context, state, child) {
        return AppShell(child: child);
      },
      routes: [
        GoRoute(
          path: '/home',
          builder: (context, state) => const HomeScreen(),
        ),
        GoRoute(
          path: '/search',
          builder: (context, state) => const SearchScreen(),
        ),
        GoRoute(
          path: '/settings',
          builder: (context, state) => const SettingsScreen(),
        ),
      ],
    ),
  ],
);
Enter fullscreen mode Exit fullscreen mode

Top comments (0)