1. 8.3.x core/lib/Drupal/Core/Routing/routing.api.php routing
  2. 8.0.x core/lib/Drupal/Core/Routing/routing.api.php routing
  3. 8.1.x core/lib/Drupal/Core/Routing/routing.api.php routing
  4. 8.2.x core/lib/Drupal/Core/Routing/routing.api.php routing
  5. 8.4.x core/lib/Drupal/Core/Routing/routing.api.php routing

Route page requests to code based on URLs.

Overview and terminology

The Drupal routing system defines how Drupal responds to URL requests that the web server passes on to Drupal. The routing system is based on the Symfony framework. The central idea is that Drupal subsystems and modules can register routes (basically, URL paths and context); they can also register to respond dynamically to routes, for more flexibility. When Drupal receives a URL request, it will attempt to match the request to a registered route, and query dynamic responders. If a match is made, Drupal will then instantiate the required classes, gather the data, format it, and send it back to the web browser. Otherwise, Drupal will return a 404 or 403 response.

The following sections of this topic provide an overview of the routing API. For more detailed information, see https://www.drupal.org/developing/api/8/routing

Registering simple routes

To register a route, add lines similar to this to a module_name.routing.yml file in your top-level module directory:

  path: '/admin/reports/dblog'
    _controller: '\Drupal\dblog\Controller\DbLogController::overview'
    _title: 'Recent log messages'
    _permission: 'access site reports'

Some notes:

  • The first line is the machine name of the route. Typically, it is prefixed by the machine name of the module that defines the route, or the name of a subsystem.
  • The 'path' line gives the URL path of the route (relative to the site's base URL). Generally, paths in Drupal are treated as case-insensitive, which overrides the default Symfony behavior. Specifically:

    • If different routes are defined for /example and /EXAmplE, the exact

    match is respected.

    • If there is no exact match, the route falls back to a case-insensitive

    match, so /example and /EXAmplE will return the same page. Relying on case-sensitive path matching is not recommended because it negatively affects user experience, and path aliases do not support case- sensitive matches. The case-sensitive exact match is currently supported only for backwards compatibility and may be deprecated in a later release.

  • The 'defaults' section tells how to build the main content of the route, and can also give other information, such as the page title and additional arguments for the route controller method. There are several possibilities for how to build the main content, including:

  • The 'requirements' section is used in Drupal to give access permission instructions (it has other uses in the Symfony framework). Most routes have a simple permission-based access scheme, as shown in this example. See the Permission system topic for more information about permissions.

See https://www.drupal.org/node/2092643 for more details about *.routing.yml files, and https://www.drupal.org/node/2122201 for information on how to set up dynamic routes. The Events topic is also relevant to dynamic routes.

Defining routes with placeholders

Some routes have placeholders in them, and these can also be defined in a module_name.routing.yml file, as in this example from the Block module:

  path: '/admin/structure/block/manage/{block}'
    _entity_form: 'block.default'
    _title: 'Configure block'
    _entity_access: 'block.update'

In the path, '{block}' is a placeholder - it will be replaced by the ID of the block that is being configured by the entity system. See the Entity API topic for more information.

Route controllers for simple routes

For simple routes, after you have defined the route in a *.routing.yml file (see Registering simple routes above), the next step is to define a page controller class and method. Page controller classes do not necessarily need to implement any particular interface or extend any particular base class. The only requirement is that the method specified in your *.routing.yml file returns:

  • A render array (see the Theme and render topic for more information). This render array is then rendered in the requested format (HTML, dialog, modal, AJAX are supported by default). In the case of HTML, it will be surrounded by blocks by default: the Block module is enabled by default, and hence its Page Display Variant that surrounds the main content with blocks is also used by default.
  • A \Symfony\Component\HttpFoundation\Response object.

As a note, if your module registers multiple simple routes, it is usual (and usually easiest) to put all of their methods on one controller class.

If the route has placeholders (see Defining routes with placeholders above) the placeholders will be passed to the method (using reflection) by name. For example, the placeholder '{myvar}' in a route will become the $myvar parameter to the method.

Additionally, if a parameter is typed to one of the following special classes the system will pass those values as well.

  • \Symfony\Component\HttpFoundation\Request: The raw Symfony request object. It is generally only useful if the controller needs access to the query parameters of the request. By convention, this parameter is usually named $request.
  • \Psr\Http\Message\ServerRequestInterface: The raw request, represented using the PSR-7 ServerRequest format. This object is derived as necessary from the Symfony request, so if either will suffice the Symfony request will be slightly more performant. By convention this parameter is usually named $request.
  • \Drupal\Core\Routing\RouteMatchInterface: The "route match" data from this request. This object contains various standard data derived from the request and routing process. Consult the interface for details.

Most controllers will need to display some information stored in the Drupal database, which will involve using one or more Drupal services (see the Services and container topic). In order to properly inject services, a controller should implement \Drupal\Core\DependencyInjection\ContainerInjectionInterface; simple controllers can do this by extending the \Drupal\Core\Controller\ControllerBase class. See \Drupal\dblog\Controller\DbLogController for a straightforward example of a controller class.


core/lib/Drupal/Core/Routing/routing.api.php, line 8
Hooks and documentation related to the routing system.


Namesort descending Location Description
ControllerBase core/lib/Drupal/Core/Controller/ControllerBase.php Utility base class for thin controllers.


Namesort descending Location Description
RouteBuilderInterface core/lib/Drupal/Core/Routing/RouteBuilderInterface.php Rebuilds the route information and dumps it.
RouteMatchInterface core/lib/Drupal/Core/Routing/RouteMatchInterface.php Provides an interface for classes representing the result of routing.