f in x
Flutter Navigation — Routes, Navigator and Deep Links for Apps That Never Get Lost
> cd .. / HUB_EDITORIALE
Sviluppo di siti web

Flutter Navigation — Routes, Navigator and Deep Links for Apps That Never Get Lost

[2026-06-28] Author: Ing. Calogero Bono
Zenithby Meteora Web Il sistema operativo della tua attività. Social, clienti, prenotazioni e fatture in un'unica piattaforma. Palestre, barber, professionisti. Scopri Zenith Demo gratis · senza carta

Have you ever opened an app and landed on the wrong screen? Or worse, a user arrives from a link and sees the home page instead of the product they searched for on Google? That's what happens when navigation is poorly managed. We, at Meteora Web, have seen projects where route handling was a mess of ad-hoc pushes and pops. Here's how to bring order.

Why is Flutter navigation different from other technologies?

Flutter doesn't use the native view system of iOS or Android. It has its own graphics engine (Skia / Impeller) and its own routing stack. This means the navigation logic is entirely under your control, but you also need to understand it deeply to avoid subtle bugs.

The Navigator widget works like a stack: each screen is a Route that gets pushed or popped. Seems simple, but when you need to handle authentication, deep links, tab bars, and data passing, things get complex.

How do you define routes in Flutter?

There are two main approaches:

Declarative Routes (Navigator 2.0)

With Router and RouteInformationParser you manage navigation as app state. Ideal for complex apps and deep links. We use the go_router package to simplify.

Sponsored Protocol

Imperative Routes (Navigator 1.0)

The classic Navigator.push and pop. Fine for small apps, but doesn't scale.

// Navigator 1.0
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => ProductDetail(id: 42)),
);

The problem? If the user receives a push notification with a different product ID, you have to manually handle the route. With Navigator 2.0 and go_router, the path is declared centrally.

How to handle deep links with Flutter and GoRouter?

Deep links allow a user to arrive directly at a specific app screen from an external link (e.g., email, Google ad). In Flutter, you must configure two things: the operating system (iOS Universal Links, Android App Links) and the Dart-side router.

With go_router, configuration is straightforward:

final router = GoRouter(
  initialLocation: '/',
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => HomeScreen(),
    ),
    GoRoute(
      path: '/product/:id',
      builder: (context, state) {
        final id = state.pathParameters['id']!;
        return ProductDetail(id: int.parse(id));
      },
      routes: [
        GoRoute(
          path: 'reviews',
          builder: (context, state) => ProductReviews(id: id),
        ),
      ],
    ),
  ],
);

Then in main.dart, wrap the app with MaterialApp.router:

Sponsored Protocol

MaterialApp.router(
  routerConfig: router,
  // ...
);

For native deep links, you also need to add the apple-app-site-association file (iOS) and assetlinks.json (Android). At Meteora Web, we automated this step with a script that generates and uploads the files to the server.

Data passing between screens: what to avoid?

Common mistake: passing complex objects as Map or serializing everything to JSON. In Flutter, the cleanest way is to use route constructors. With go_router, you can pass extra:

context.go('/product/42', extra: {'utm': 'email', 'campaign': 'spring'});

Then in the builder read it with state.extra. Simple and traceable.

Conditional navigation: login, onboarding, and user state

Many apps need to redirect the user based on authentication state. With go_router you can use redirect:

Sponsored Protocol

final router = GoRouter(
  redirect: (context, state) {
    final isLoggedIn = AuthService.isLoggedIn;
    final isOnLoginPage = state.matchedLocation == '/login';

    if (!isLoggedIn && !isOnLoginPage) return '/login';
    if (isLoggedIn && isOnLoginPage) return '/';
    return null;
  },
  // ...
);

Warning: avoid infinite redirect loops. return null means no redirect.

How to test navigation in Flutter?

We write widget tests for every critical route. With go_router you can create a test router and inject fake dependencies:

testWidgets('Deep link opens product screen', (tester) async {
  await tester.pumpWidget(
    MaterialApp.router(
      routerConfig: GoRouter(
        initialLocation: '/product/123',
        routes: [/* ... */],
      ),
    ),
  );
  expect(find.text('Product Detail 123'), findsOneWidget);
});

Don't forget integration tests for real deep links: simulate an incoming link from the operating system.

Common navigation mistakes in Flutter and how to avoid them

Don't use Navigator.push inside an async callback without the right context

The context might be unmounted. Use context.mounted (Flutter 3.7+) or a global navigatorKey.

Sponsored Protocol

Ignoring PopScope (or WillPopScope)

If the user presses back during a save, you can show a dialog. With PopScope you block the pop until safe.

PopScope(
  canPop: false,
  onPopInvokedWithResult: (didPop, _) {
    if (!didPop) {
      // Show confirmation dialog
      showDialog(...);
    }
  },
  child: Scaffold(...),
);

What to do now

Here are three concrete actions to improve navigation in your Flutter app:

  1. Replace Navigator.push with go_router if you have more than 5 screens. Run: flutter pub add go_router.
  2. Set up deep links for iOS and Android following the official Flutter guide. Create the JSON files and verify them with Google's testing tool.
  3. Add an authentication redirect using the redirect property of GoRouter. Test it with a non-logged-in user.

Want to dive deeper? Read our Flutter Pillar for a complete view of cross-platform development.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ Read Full Dossier ]

> METEORA_WEB // DIGITAL AGENCY

We build the digital presence your business deserves.

Websites, social media, online advertising, e-commerce and high-performance hosting, engineered with method by computer engineers in Sciacca, for all of Italy.

> MW_JOURNAL

> READ_ALL()