Declare, read, and validate route parameters in Aurelia's router, including required, optional, wildcard, and constrained segments.
Route parameters let you map dynamic pieces of a URL to runtime data. This guide covers how to declare each parameter style, consume values inside components, and coordinate parent/child segments.
1. Declare parameterized paths
Use the path field inside @route (or route configs) to describe parameters.
Each lifecycle hook receives a Params object. The router always supplies a string value (or undefined if optional and missing), so add your own parsing as needed.
For asynchronous preparation, use loading and throw to fail the navigation (or return false from canLoad) if something looks wrong.
2. Access parent and child parameters together
Nested routes often need both parent and child IDs (for example /companies/10/projects/17). Resolve IRouteContext and use getRouteParameters to aggregate values.
Callers can opt in to query parameters too:
3. Work with query parameters alongside path params
Even though query parameters are not part of the path definition, you can treat them as a cohesive set.
The load attribute on <a> elements handles interpolation for you. Bind params to an object so that the router formats the URL consistently. When you use route: ... with params.bind, the value must be a route id (not a path pattern).
If you prefer to write a literal path, skip route: and provide the full string yourself:
When generating programmatic instructions, pass params alongside the component:
5. Validate and coerce parameters
Guard logic belongs in the canLoad hook. You can redirect by returning a string instruction or a ViewportInstruction.
For stricter validation, pair regex-constrained paths with canLoad type checks so users get feedback before hitting your backend.
6. Test parameterized routes
Unit tests can render a component, navigate to a parameterized path, and assert how parameters flow through the lifecycle.
You can also mock IRouteContext or ICurrentRoute to simulate specific parameter sets without spinning up the full router.
Outcome recipes
Bookmarkable search filters
Goal: encode search term, page number, and filter chips in the URL so users can share the view.
Define the base route /search and keep filters in the query string (?q=aurelia&page=2&tag=forms).
Use ICurrentRoute.query to read the current filters in attached() and hydrate your form.
When filters change, call router.load(this.current.path, { queryParams: newFilters }) to update the URL without reloading the whole app.
Checklist:
Refreshing /search?q=router&page=3 shows the same filter state.
router.load uses historyStrategy: 'replace' when only filters change to avoid polluting history (configure via navigation options if needed).
Parent + child identifiers
Goal: address /companies/:companyId/projects/:projectId and display both IDs in deeply nested children.
Parent route declares companies/:companyId and renders a <au-viewport> for projects.
Child route declares projects/:projectId.
Inside any descendant component call routeContext.getRouteParameters({ mergeStrategy: 'parent-first' }) to get both IDs.
Checklist:
Navigating between different projects preserves the company context.
routeContext.getRouteParameters() returns { companyId: '10', projectId: '17' } at every depth.
Redirect invalid params
Goal: keep /reports/:date constrained to valid ISO dates.
Constrain the route with :date{{^\\d{4}-\\d{2}-\\d{2}$}} to block obviously bad paths.
Inside canLoad, parse the date and return 'reports/today' if invalid.
Emit a toast notification through a shared service to explain the redirect.
Checklist:
/reports/2024-13-01 never renders the detail view; users land on /reports/today.