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.