Specifying Route Paths in Drupal: Dynamic URL Placeholdersfor Drupal 8 , 9 , 10 , and 11

Last updated :  

A path like /examples/page-example/simple only ever matches that one exact URL. But most real pages need to react to something in the URL itself — a user ID, a node number, a search term. Rather than writing a separate route for every possible value, Drupal lets you carve out a placeholder in the path and hand whatever the visitor typed straight to your controller as a real PHP argument.

What you'll learn in this lesson

  • How curly-brace placeholders in a path capture part of the URL
  • How placeholder names map directly onto your controller method's parameters
  • What happens when a visitor requests a URL that doesn't match any defined path

A route with dynamic segments

Here's a real route from Drupal's Examples module that accepts two values straight from the URL:

page_example.arguments:
  path: '/examples/page-example/arguments/{first}/{second}'
  defaults:
    _controller: '\Drupal\page_example\Controller\PageExampleController::arguments'
  requirements:
    _permission: 'access arguments page'

Visiting /examples/page-example/arguments/5/10 matches this route, with {first} capturing 5 and {second} capturing 10.

The placeholder names must match your method's parameter names

public function arguments($first, $second) {
  // $first is '5', $second is '10'.
}

This is the detail that trips people up the first time: {first} and {second} in the YAML aren't arbitrary labels — Drupal's routing system matches them by name to the parameters of your controller method. Name a placeholder {uid} in the path and your method needs a $uid parameter to receive it, in whatever position it appears.

What if the URL doesn't match anything?

If a visitor requests a path that doesn't correspond to any defined route — with or without placeholders — Drupal returns a standard 404 page. There's no partial matching: either every static segment lines up and every placeholder has a value, or the route simply isn't considered a match.

Gotcha: a placeholder captures exactly one URL segment (the text between two slashes) — it can never span a /. If you need to capture something that might contain slashes, you need a different approach entirely (a wildcard route or query parameters), not a bigger placeholder.

Quick check: your route path is /report/{year}/{month} and your controller method is declared as public function report($month, $year) — parameter order reversed from the path. Does this still work? Yes — Drupal matches placeholders to parameters by name, not by position, so $year and $month still receive the correct values regardless of which order they're declared in.

Key takeaways

  • Curly braces in a path (like {first}) mark a dynamic segment that Drupal captures from the URL.
  • Placeholder names must exactly match the corresponding parameter names in your controller method — matching is by name, not position.
  • Each placeholder captures exactly one URL segment; it can never contain a literal /.
  • A URL that doesn't match any route's static text and placeholders returns a standard 404 — there's no fuzzy matching.

Coming up next

Capturing a value from the URL is only half the story — often you also need to validate or constrain what that value can be before your controller ever runs. The next lesson, Defining Route Requirements, covers exactly that.