Wildcard routes (dynamic URL segments)
Use wildcard routes so one page can serve many URLs with dynamic segments—for example a single “guided course” page that works for every course and module:/app/guided-courses/foundations/module-1, /app/guided-courses/advanced/lesson-5, and so on.
How it works
- You create one page whose URL pattern includes placeholders like
{course}and{module}. - When a visitor opens a URL that matches that pattern, they see that page, and the segments from the URL are available in the template as
route_params(and asroute_slug). - You can have multiple such pages with different patterns (e.g. one for courses, one for workshops).
{course}, {module}, {id}, etc.
Setting up a wildcard route
1. Create the page
In the app, create a page that will handle all URLs under a path, for example:- Path/slug pattern:
app/guided-courses/{course}/{module}
- The fixed part is:
app/guided-courses - The dynamic parts are:
{course}and{module}
2. What URLs will match
Once that page exists, URLs like these will all show the same page, with different segment values:| URL | route_params.course | route_params.module |
|---|---|---|
/app/guided-courses/foundations/module-1 | foundations | module-1 |
/app/guided-courses/advanced/lesson-5 | advanced | lesson-5 |
/app/guided-courses/intro/welcome | intro | welcome |
/app/guided-courses (no extra segments) also matches this page; in that case there are no dynamic segments, so route_params will be empty/null as appropriate.
Using the segments in your template
Two things are available in the template:route_params– Object with one key per placeholder, e.g.{ course: 'foundations', module: 'module-1' }. Use this when you named your placeholders (e.g.{course},{module}).route_slug– The full “rest of the path” as one string, e.g.foundations/module-1. Useful when you have a single placeholder or want the whole tail.
Displaying the current segment
Using the course slug in a template function
For a guided-course page you often want to load the course by the slug from the URL:route_params.course); getCourseBySlug does not read the URL by itself.
Single dynamic segment
If your page slug is something likeapp/guided-course/{slug} (one placeholder), then you have one segment:
route_params.segment_0– The first (and only) segment, e.g.intro-to-js.route_slug– Same value, e.g.intro-to-js.
Checking that segments exist
For non-wildcard URLs,route_params and route_slug are not set (or are null). You can guard your logic:
Examples
One placeholder: “course by slug”
- Page slug:
app/guided-course/{slug} - URLs:
/app/guided-course/foundations,/app/guided-course/advanced, … - In template:
route_params.segment_0orroute_slugis the course slug (e.g.foundations). Pass it togetCourseBySlug(route_params.segment_0).
Two placeholders: “course + module”
- Page slug:
app/guided-courses/{course}/{module} - URLs:
/app/guided-courses/foundations/module-1, … - In template:
route_params.course,route_params.module. UsegetCourseBySlug(route_params.course)and then useroute_params.moduleto pick the right module or lesson.
More segments
You can use as many placeholders as you need, for example:- Page slug:
learn/{topic}/{level}/{lesson} - URL:
/learn/javascript/beginner/01-variables - In template:
route_params.topic,route_params.level,route_params.lesson.
Tips
- Placeholder names – Use names that make sense in your template (e.g.
course,module,lesson). They become the keys ofroute_params. - Same page, many URLs – One page with a wildcard slug serves every matching URL; the content can change based on
route_paramsandroute_slug. - Multiple wildcard pages – You can have several pages with different patterns (e.g.
app/guided-courses/{course}/{module}andapp/workshops/{slug}). Each pattern is matched separately; the right page is chosen by the URL.
Summary
| You want… | Page slug (in app) | In template |
|---|---|---|
| One segment (e.g. course slug) | app/guided-course/{slug} | route_params.segment_0 or route_slug |
| Named segments (e.g. course + module) | app/guided-courses/{course}/{module} | route_params.course, route_params.module |
| Full remainder as one string | Any wildcard page | route_slug |
{name} in the slug for each dynamic part, then use route_params.name (or route_slug) in the template to drive your content and logic.
Using a wildcard segment to drive locale ({hl})
If you want clean URLs like /en/about or /pt-br/checkout to switch
the active locale, capture the locale segment with a placeholder named
hl (or any name you prefer, then read it from route_params and pass
it through ?hl=).
- Page slug:
{hl}/about - URL:
/en/about,/pt-br/about - In template:
route_params.hlisen/pt-br
req.params.hl first when picking
the active locale. See Internationalization (i18n)
for the full precedence chain (hl path segment → ?hl → ?locale
→ ?lang → session/domain/brand defaults → Accept-Language).