Setting Route Parameters in Drupal: Entity Upcasting Explainedfor Drupal 8 , 9 , 10 , and 11

Last updated :  

You already know a URL placeholder like {node} hands your controller a raw string. But raw strings aren't always what you actually want — most of the time, an ID in a URL exists to identify a real entity, and you'd rather work with the loaded object than write a manual lookup every single time. Route parameters let you tell Drupal to do that loading for you, automatically, before your controller method ever runs.

What you'll learn in this lesson

  • How entity upcasting turns a raw ID in the URL into a loaded entity object
  • The naming convention that makes upcasting work automatically
  • How to pass extra options to a parameter using the parameters key

Entity upcasting: the URL parameter becomes a real object

my_module.node_view:
  path: '/my-module/node/{node}/summary'
  defaults:
    _controller: '\Drupal\my_module\Controller\MyController::summary'
  requirements:
    _permission: 'access content'
public function summary(\Drupal\node\NodeInterface $node) {
  // $node is already a fully loaded Node entity — not a numeric string.
  return ['#markup' => $this->t('Viewing: @title', ['@title' => $node->label()])];
}

Notice the placeholder is named {node} — matching the entity type ID of the node entity type exactly. That match is what triggers Drupal's parameter conversion system: instead of handing your method the raw string "42", it loads the actual Node entity with that ID and hands you the object. If no node with that ID exists, Drupal automatically returns a 404 before your controller runs at all — you never have to write that check yourself.

This works for any entity type, not just nodes

Name a placeholder {user}, {taxonomy_term}, or the machine name of any content or config entity type, and the same automatic loading applies — Drupal recognizes the entity type ID and converts the parameter for you.

Overriding conversion behavior with parameters

my_module.node_view:
  path: '/my-module/node/{node}/summary'
  defaults:
    _controller: '\Drupal\my_module\Controller\MyController::summary'
  requirements:
    _permission: 'access content'
  options:
    parameters:
      node:
        type: entity:node

In simple cases the {node}-name-matches-entity-type-id convention is all you need, and this explicit options.parameters block is redundant. It becomes necessary when the placeholder name doesn't match the entity type ID (say, you named it {article} for readability) — this block tells Drupal explicitly which entity type to load for that specific parameter name.

Gotcha: upcasting only fires automatically when the placeholder name exactly matches an entity type ID. Name your placeholder {article} without an explicit parameters override, and your controller receives the raw string "42", not a loaded node — a common source of confusion when refactoring a route's placeholder names.

Quick check: your route has {user} in its path and your controller method type-hints its parameter as \Drupal\user\UserInterface $user. A visitor requests a user ID that doesn't exist. What happens? Drupal returns a 404 automatically, before your method body runs — the same entity-not-found handling applies uniformly across every upcast entity type.

Key takeaways

  • Name a placeholder to match an entity type ID (like {node}) and Drupal automatically loads that entity, handing your controller the object instead of a raw string.
  • Type-hint the corresponding controller parameter with the entity's interface to make this explicit and get IDE autocompletion.
  • A non-existent entity ID in an upcast parameter results in an automatic 404 — no manual lookup or error handling required.
  • Use options.parameters to explicitly declare the entity type when your placeholder name doesn't match it automatically.

Coming up next

With paths, requirements, and parameters covered, it's time to look at the other side of a route: the _controller key itself, and exactly how Drupal resolves it to a real class and method. The next lesson, Mapping Routes to Controllers, covers that mapping in detail.