Portfolio/Writing

Daksh Nauni

A Senior Software Engineer developing softwares, hands on with mobile and web applications and backend systems.

Navigation

  • Home
  • Projects
  • Blog
  • Contact

© 2026 Daksh Nauni. All rights reserved.

Flutter

Getx and GoRouter without Bindings in Flutter Web

Use GoRouter with GetX without Bindings in Flutter Web. Learn how to inject controllers, pass route params, avoid duplicates, and support deep linking safely.

Daksh Nauni·April 13, 2026·3 min read
Getx with GoRouter without Bindings in Flutter

Intro

Routing + state management in Flutter and especially Flutter Web often gets messy when combining GoRouter and GetX.

I was in exactly same situation where I was facing bugs while using bindings in Flutter Web. And I could not ditch GoRouter since navigation in Flutter web becomes very difficult without it.

This guide shows a simple, repeatable pattern to use GoRouter + GetX controllers without Bindings and Flutter Web compatible.

In this guide you’ll learn how to:

  • Inject controllers directly from GoRouter
  • Pass route parameters into controllers safely
  • Access controllers inside widgets
  • Prevent duplicate controller instances using tags

GoRouter handles navigation and deep linking. GetX is used purely for dependency injection and state management.

Project Dependencies

go_router: ^16.3.0

get: ^4.7.2

The Problem

When you have Getx and GoRouter together then you’re gonna face these issues:

1) Bindings don’t naturally fit GoRouter

GoRouter uses a builder pattern and supports deep links, redirects, and web URLs. Bindings introduce an extra abstraction layer that becomes difficult to control.

2) Route parameters become awkward

You often need route parameters inside controllers, but bindings don’t receive GoRouter parameters cleanly.

3) Deep linking breaks expectations

If a user opens a URL directly (web or refresh), you must guarantee the controller is ready before UI builds.

4) Duplicate controller instances

Opening multiple tabs like:

/brand/1

/brand/2

/brand/1 (another tab)

can lead to:

  • Controller conflicts
  • Old data being reused
  • Get.find() errors

Solution

Since we can’t use the Bindings from Getx, we just have to treat GoRouter builder as your binding.

We inject controllers inside the route builder using route parameters.

Step 1 - Create Controller With Constructor Parameters

Your controller should receive all required data directly via constructor. This makes the controller fully self-contained and easy to test.

dart
class BrandDetailsController extends GetxController {
  final String clientId;
  final String brandId;

  BrandDetailsController({
    required this.clientId,
    required this.brandId,
  });

  // API calls → onInit / onReady
}

Step 2 - Inject Controller Inside GoRouter Builder

Extract parameters from the route and inject the controller using Get.put().

dart
GoRoute(
  name: AppRouteNames.brandDetails,
  path: AppRoutePaths.brandDetails,
  redirect: (context, state) {
    final auth = Get.find<AuthService>();
    if (auth.getToken() == null) {
      return AppRoutePaths.login;
    }
    return null;
  },
  builder: (context, state) {
    final brandId = state.pathParameters['id']!;

    Get.put(
      BrandDetailsController(
        clientId: brandId,
        brandId: brandId,
      ),
      tag: "${brandId}_$brandId",
    );

    return BrandDetailsScreen(
      clientId: brandId,
      brandId: brandId,
      adminView: false,
    );
  },
);

We are injecting inside builder because :

  • Works when user enters URL directly
  • Route parameters are instantly available
  • No need for GetX Bindings
  • Controller is ready before UI loads

Step 3 - Access Controller Inside the UI

Use the same tag when calling Get.find() in the UI.

dart
final brandDetailsCtrl = Get.find<BrandDetailsController>(
  tag: "${brandId}_$brandId",
);

Now you get access to the controller instance in the UI like any other Getx project.

Result

This pattern gives you the best of both worlds:

Clean architecture

  • GoRouter handles navigation
  • GetX handles DI + state
  • No extra binding layer

Perfect deep link support

Controllers are created even when users open URLs directly.

Safe multi-tab behavior

Using tags ensures:

  • No controller conflicts
  • Each page/tab gets its own instance
  • No stale data reuse
  • No Get.find() errors

You now have a simple, production-ready pattern for using GoRouter with GetX without bindings perfect for Flutter Web and mobile.

That’s all ! Still got some issues? Feel free to contact me.
Thanks for reading.

Daksh Nauni

Daksh Nauni

I am a software engineer who enjoys building mobile apps, web platforms, and backend systems. This blog is where I share what I learn while building real projects, from debugging weird errors to shipping features that actually matter.

View portfolioContact

Work with me

Building an app or web product?

I work with startups and small teams to ship polished, performant web and mobile products. If you have something worth building, I'd love to hear about it.

View Portfolio

or Get in touch

On this page

  • Intro
  • Project Dependencies
  • The Problem
  • 1) Bindings don’t naturally fit GoRouter
  • 2) Route parameters become awkward
  • 3) Deep linking breaks expectations
  • 4) Duplicate controller instances
  • Solution
  • Step 1 - Create Controller With Constructor Parameters
  • Step 2 - Inject Controller Inside GoRouter Builder
  • Step 3 - Access Controller Inside the UI
  • Result
  • Clean architecture
  • Perfect deep link support
  • Safe multi-tab behavior

Related Articles

Fixing Next JS Heap Memory Exhaustion in next dev
FixErrorNextJS

Fixing Next JS Heap Memory Exhaustion in next dev

Next.js crashed with “JavaScript heap out of memory” during next dev. The cause was Turbopack caching and Tailwind v4 scanning. This post explains the root cause and the simple fixes that stopped it.

April 10, 20262 min read