Skip to content

Passing Multiple Parameters with GoRouter in Flutter ​

When migrating from Flutter's standard navigation to go_router, developers often struggle with passing multiple parameters between screens. While the traditional Navigator.push approach allows straightforward object passing, go_router requires different techniques depending on your use case.

Problem: Passing Complex Data Between Routes ​

With standard Flutter navigation, you could pass multiple parameters directly:

dart
Navigator.of(context).push(MaterialPageRoute(
  builder: (_) => CatalogFilterPage(
    list: list,
    bloc: bloc,
  )));

With go_router, you need alternative approaches since the params parameter only accepts Map<String, String>.

Solution Approaches ​

GoRouter offers three primary methods for passing data between routes:

1. Using pathParameters for Known Parameters ​

When you know the number and names of parameters in advance, use path parameters:

dart
// Route definition
GoRoute(
  path: '/sample/:id1/:id2',
  name: 'sample',
  builder: (context, state) => SampleWidget(
    id1: state.pathParameters['id1']!,
    id2: state.pathParameters['id2']!,
  ),
),

// Navigation
context.goNamed(
  "sample", 
  pathParameters: {'id1': 'value1', 'id2': 'value2'}
);

WARNING

Path parameters are always strings. You'll need to convert them to appropriate types (int, double, etc.) in your destination widget.

2. Using queryParameters for Flexible Parameters ​

When you need flexibility in the number of parameters or want to support optional parameters:

dart
// Route definition
GoRoute(
  path: '/sample',
  name: 'sample',
  builder: (context, state) => SampleWidget(
    id1: state.uri.queryParameters['id1'],
    id2: state.uri.queryParameters['id2'],
  ),
),

// Navigation options
context.goNamed(
  "sample", 
  queryParameters: {'id1': 'value1', 'id2': 'value2'}
);

// OR
context.go("/sample?id1=value1&id2=value2");

INFO

Query parameters are ideal for web compatibility as they appear in the URL, making routes shareable and bookmarkable.

3. Using extra for Complex Objects ​

When you need to pass complex objects (like models, blocs, or custom classes):

dart
// Route definition
GoRoute(
  path: '/sample',
  builder: (context, state) {
    final args = state.extra as Map<String, dynamic>;
    return CatalogFilterPage(
      list: args['list'] as ListItemsModel,
      bloc: args['bloc'] as CatalogBloc,
    );
  },
),

// Navigation
context.pushNamed(
  'sample',
  extra: {
    'list': list,
    'bloc': bloc,
  },
);

TIP

The extra parameter is type-unsafe and requires casting. Consider creating a dedicated data class for your route arguments to improve type safety.

Best Practices ​

For Simple Data (IDs, names, flags) ​

Use pathParameters or queryParameters:

dart
// For required parameters
path: '/user/:userId/profile/:tab'

// For optional parameters
path: '/search'
// Then use queryParameters: {'q': query, 'sort': 'date'}

For Complex Objects ​

Use the extra parameter with a typed map:

dart
// Create a typed wrapper class for better safety
class CatalogArgs {
  final ListItemsModel list;
  final CatalogBloc bloc;
  
  CatalogArgs({required this.list, required this.bloc});
}

// Usage
context.pushNamed('catalog', extra: CatalogArgs(list: list, bloc: bloc));

Version Compatibility Note ​

WARNING

Be aware of breaking changes in go_router versions:

  • Below 7.0.0: Use params and queryParams
  • 7.0.0 to 10.0.0: Use pathParameters and queryParameters
  • 10.0.0 and above: Use pathParameters and uri.queryParameters

Complete Example ​

dart
// routes.dart
GoRoute(
  path: '/catalog-filter',
  name: 'catalogFilter',
  builder: (context, state) {
    // For object passing
    final args = state.extra as Map<String, dynamic>;
    
    return CatalogFilterPage(
      list: args['list'] as ListItemsModel,
      bloc: args['bloc'] as CatalogBloc,
      // For query parameters
      sortBy: state.uri.queryParameters['sortBy'],
      // For path parameters (if defined in path)
      category: state.pathParameters['category'],
    );
  },
),

// navigation.dart
context.pushNamed(
  'catalogFilter',
  pathParameters: {'category': 'electronics'},
  queryParameters: {'sortBy': 'price'},
  extra: {
    'list': list,
    'bloc': bloc,
  },
);

Conclusion ​

GoRouter provides multiple ways to pass parameters between routes, each with its own use cases:

  • pathParameters: For required, structured parameters
  • queryParameters: For optional or flexible parameters
  • extra: For complex objects that shouldn't be serialized in the URL

Choose the approach that best fits your data structure and application requirements, keeping in mind version compatibility and type safety considerations.