NavigationUtils extends Navigator 2 with full support for query parameters and path parameters. This guide explains how to define, pass, and access routing parameters in your application.
Overview
Navigator 2 does not support query parameters or path parameters out of the box. NavigationUtils adds this functionality by extending PageRoute with DefaultRoute and building an abstraction layer through NavigationData.
All URL parameters are passed as Strings because URLs are not “typed” by default.
- Extract
ints and doubles with int.tryParse() and double.tryParse()
- Extract
bools by comparing strings: routeData.queryParameters['flag'] == 'true'
Query parameters
Query parameters are key-value pairs appended to the URL after a ? symbol. They’re ideal for optional data, filters, search queries, and pagination.
Defining routes with query parameters
Access query parameters via routeData.queryParameters in your NavigationData builder:
NavigationData(
label: ProjectPage.name,
url: '/project',
builder: (context, routeData, globalData) => ProjectPage(
id: int.tryParse(routeData.queryParameters['id'] ?? ''),
),
)
Navigating with query parameters
// Using named route
NavigationManager.instance.push(
ProjectPage.name,
queryParameters: {'id': '320'},
);
// Using path route
NavigationManager.instance.push(
'/project',
queryParameters: {'id': '320'},
);
// Direct URL navigation
NavigationManager.instance.push('/project?id=320');
Multiple query parameters
NavigationData(
url: '/products',
builder: (context, routeData, globalData) => ProductsPage(
category: routeData.queryParameters['category'],
sort: routeData.queryParameters['sort'] ?? 'recent',
page: int.tryParse(routeData.queryParameters['page'] ?? '1') ?? 1,
),
)
Navigation:
NavigationManager.instance.push(
'/products',
queryParameters: {
'category': 'electronics',
'sort': 'price',
'page': '2',
},
);
Updating query parameters
Update query parameters without navigating to a new page:
NavigationManager.instance.setQueryParameters({
'filter': 'active',
'sort': 'recent',
});
Query parameters are extracted from URLs and stored separately in NavigationUtils. This ensures that routes with different query parameters are treated as the same page, with parameters passed to that page.
Path parameters
Path parameters are dynamic segments within the URL path, denoted by a colon (:) prefix. They’re ideal for required identifiers and hierarchical data.
Defining routes with path parameters
Define path parameters in the url property using :parameterName syntax:
NavigationData(
label: ProjectPage.name,
url: '/project/:projectId',
builder: (context, routeData, globalData) => ProjectPage(
id: int.tryParse(routeData.pathParameters['projectId'] ?? ''),
),
)
Navigating with path parameters
// Using named route with path parameters
NavigationManager.instance.push(
ProjectPage.name,
pathParameters: {'projectId': '320'},
);
// Direct URL navigation
NavigationManager.instance.push('/project/320');
Multiple path parameters
NavigationData(
label: PostPage.name,
url: '/user/:userId/posts/:postId',
builder: (context, routeData, globalData) => PostPage(
userId: routeData.pathParameters['userId'] ?? '',
postId: routeData.pathParameters['postId'] ?? '',
),
)
Navigation:
// Using path parameters map
NavigationManager.instance.push(
PostPage.name,
pathParameters: {
'userId': '42',
'postId': '128',
},
);
// Direct URL navigation
NavigationManager.instance.push('/user/42/posts/128');
Path parameter considerations
/project and /project/:projectId are different URLs. To support both patterns, define separate NavigationData instances:NavigationData(
url: '/project',
builder: (context, routeData, globalData) => ProjectListPage(),
),
NavigationData(
url: '/project/:projectId',
builder: (context, routeData, globalData) => ProjectPage(
id: int.tryParse(routeData.pathParameters['projectId'] ?? ''),
),
)
A trailing slash like /project/ does not pass a null ID to /project/:projectId. Instead, /project/ is equivalent to /project.
Combining query and path parameters
You can use both types of parameters together:
NavigationData(
url: '/article/:articleId',
builder: (context, routeData, globalData) => ArticlePage(
id: routeData.pathParameters['articleId'] ?? '',
referrer: routeData.queryParameters['ref'],
highlight: routeData.queryParameters['highlight'],
),
)
Navigation:
// Using parameters map
NavigationManager.instance.push(
'/article/:articleId',
pathParameters: {'articleId': '123'},
queryParameters: {'ref': 'twitter', 'highlight': 'intro'},
);
// Direct URL
NavigationManager.instance.push('/article/123?ref=twitter&highlight=intro');
Real-world examples
Deeplinks with parameters
NavigationData(
label: ProjectPage.name,
url: '/project',
builder: (context, routeData, globalData) => ProjectPage(
id: int.tryParse(routeData.queryParameters['id'] ?? ''),
),
)
Use cases:
// From email link
push('/project?id=1');
// From social media share
push('/project?id=2');
Search with filters
NavigationData(
url: '/search',
builder: (context, routeData, globalData) => SearchPage(
query: routeData.queryParameters['q'] ?? '',
filters: routeData.queryParameters['filters'],
),
)
Navigation:
push('/search?q=flutter');
push('/search?q=dart&filters=recent');
NavigationData(
url: '/list',
builder: (context, routeData, globalData) => ListPage(
page: int.tryParse(routeData.queryParameters['page'] ?? '1') ?? 1,
),
)
Navigation:
push('/list?page=1');
push('/list?page=2');
Product catalog with filtering
NavigationData(
url: '/products',
builder: (context, routeData, globalData) => ProductsPage(
category: routeData.queryParameters['category'],
),
)
Navigation:
push('/products');
push('/products?category=electronics');
Implementation details
How query parameters work
Navigator 2 treats the entire URL (including query parameters) as a unique page identifier. This means:
/
/?tab=community_page
/?tab=community_page&post=80
/?tab=message_page
/?referrer=google_ads
Would all be treated as different pages by default.
NavigationUtils solves this by:
- Extracting query parameters from the URL
- Storing them in the
DefaultRoute object
- Passing only the base path to Navigator 2
- Rebundling parameters during route construction
This ensures all variations of the same path are treated as the same page, with query parameters passed as data.
Path parameter matching
Path parameters use pattern matching to extract values:
// Pattern: '/project/:projectId'
// URL: '/project/320'
// Result: pathParameters = {'projectId': '320'}
The matching algorithm:
- Splits the URL pattern by
/
- Identifies segments starting with
:
- Extracts corresponding values from the actual URL
- Stores them in a
Map<String, String>
Passing non-serializable data
For complex objects that can’t be serialized into URLs, use globalData:
// Route Definition
NavigationData(
label: PostPage.name,
url: '/post',
builder: (context, routeData, globalData) => PostPage(
postModel: globalData['postModel'],
),
)
// Route Navigation
PostModel postModel = PostModel();
NavigationManager.instance.push(
PostPage.name,
data: {'postModel': postModel},
);
Accessing globalData
You can access and modify globalData at any time:
// Set data
NavigationManager.instance.routerDelegate.globalData['selected_variant'] = 'A';
// Access data
String variant = NavigationManager.instance.routerDelegate.globalData['selected_variant'];
globalData is not bound to the page lifecycle. Variables must be manually disposed or cleared. The URL of the page is used as the key for storing data.
Type conversion helpers
Since all parameters are strings, here are common conversion patterns:
Integer parameters
final id = int.tryParse(routeData.queryParameters['id'] ?? '') ?? 0;
Double parameters
final price = double.tryParse(routeData.queryParameters['price'] ?? '') ?? 0.0;
Boolean parameters
final isActive = routeData.queryParameters['active'] == 'true';
Enum parameters
enum SortType { recent, popular, oldest }
final sortType = SortType.values.firstWhere(
(e) => e.name == routeData.queryParameters['sort'],
orElse: () => SortType.recent,
);
List parameters
// URL: /products?tags=flutter,mobile,dart
final tags = routeData.queryParameters['tags']?.split(',') ?? [];
Comparison with Navigator 1
Navigator 1 only supported arguments, which are not query parameters:
Important: Arguments are NOT query parameters or related to URL routing in any way. Arguments are an internal parameter used to pass data between pages from the Legacy Navigator 1 implementation.
NavigationUtils properly implements URL-based routing with real query and path parameters that work with:
- Deep links
- Web URLs
- Browser back/forward buttons
- Bookmarks
- Share links
Use query parameters for optional data like filters and sorting. Use path parameters for required identifiers like IDs. Use globalData for non-serializable objects.