Core Architecture - Routing System

The Routing System is a core architectural component of Drupal that connects incoming HTTP requests to executable code. Every page request, form submission, REST endpoint, and AJAX callback in Drupal passes through the routing system.

Starting with Drupal 8, Drupal adopted Symfony’s Routing component. This was a major architectural shift from the menu based routing system used in Drupal 7. The modern routing system is declarative, object oriented, cache aware, and tightly integrated with access control, controllers, and dependency injection.

The goal here is to understand how Drupal routes requests internally, not just how to define a route.

Why Routing Belongs in Core Architecture

Routing is not a UI feature. It is a fundamental request handling mechanism.

Drupal’s routing system is responsible for:

  • Mapping URLs to controllers or forms
  • Enforcing access checks
  • Resolving route parameters
  • Integrating with the service container
  • Supporting multilingual paths
  • Enabling cacheability metadata

Without routing, Drupal cannot respond to a single HTTP request.

High Level Request Flow

Understanding routing starts with understanding the request lifecycle.

  1. Browser sends an HTTP request
  2. Symfony HttpKernel receives the request
  3. Router matches the URL to a route
  4. Access checks are executed
  5. Route parameters are resolved
  6. Controller or form is executed
  7. Response object is returned

Routing sits at the center of this flow.

What Is a Route in Drupal

A route is a definition that maps a URL path to executable code.

A route defines:

  • The URL path
  • The controller or form to execute
  • Access requirements
  • Parameter constraints
  • Defaults and options

Routes are declared using YAML files.

Route Definition File

Routes are defined in a module’s routing file.

Example: my_module.routing.yml

my_module.example:
  path: '/my-module/example'
  defaults:
    _controller: '\\Drupal\\my_module\\Controller\\ExampleController::content'
    _title: 'Example Page'
  requirements:
    _permission: 'access content'

Key parts:

  • Route name must be unique
  • Path defines the URL
  • Defaults define what executes
  • Requirements control access

Controllers and Routing

Most routes point to controllers.

A controller is a PHP class method that returns a render array or a response object.

namespace Drupal\my_module\Controller;

use Drupal\Core\Controller\ControllerBase;

class ExampleController extends ControllerBase {

  public function content() {
    return [
      '#markup' => 'Hello from routing system',
    ];
  }
}

The routing system instantiates the controller using the service container.

Routing to Forms

Routes can directly point to forms.

my_module.example_form:
  path: '/my-module/example-form'
  defaults:
    _form: '\\Drupal\\my_module\\Form\\ExampleForm'
    _title: 'Example Form'
  requirements:
    _permission: 'access content'

Drupal automatically builds and processes the form when this route is matched.

Access Control in Routing

Access control is part of routing, not controller logic.

Common access keys:

  • _permission
  • _role
  • _custom_access

Example using permission:

requirements:
  _permission: 'administer site configuration'

Custom access uses an access check service.

requirements:
  _custom_access: '\\Drupal\\my_module\\Access\\ExampleAccess::access'

Access checks run before the controller is executed.

Route Parameters

Routes can include dynamic parameters.

path: '/node/{node}'

Drupal automatically converts parameters using parameter converters.

Example controller:

public function content(NodeInterface $node) {
  return ['#markup' => $node->label()];
}

This conversion is handled by the routing system and entity type manager.

Parameter Constraints

You can restrict parameter values.

requirements:
  node: '\\d+'

This improves route matching performance and correctness.

Route Options

Options provide additional metadata.

Common options:

  • _admin_route
  • parameters
  • no_cache

Example:

options:
  _admin_route: TRUE

Admin routes receive admin theme and different caching behavior.

Route Caching

Routes are compiled and cached.

Drupal builds a route cache during cache rebuild.

Important points:

  • Routing is not evaluated on every request
  • YAML is compiled into PHP
  • Route cache improves performance

Changing routing files requires a cache rebuild.

Multilingual Routing

Drupal supports translated paths.

Example:

  • /about
  • /es/sobre

Routing integrates with:

  • Language negotiation
  • Path aliases
  • Content translation

The routing system resolves language specific paths automatically.

Drupal 10 and 11 Best Practices

  • Keep routes declarative
  • Move logic into controllers or services
  • Use dependency injection in controllers
  • Use access checks instead of if statements
  • Avoid heavy logic during routing

Common Mistakes

  • Performing access checks inside controllers
  • Using hardcoded URLs
  • Forgetting cache rebuild after route changes
  • Overusing custom access checks
  • Returning responses instead of render arrays unnecessarily

Routing Compared to Drupal 7

Drupal 7:

  • hook_menu
  • Procedural callbacks
  • Mixed routing and access logic

Drupal 8+:

  • YAML based routing
  • Controllers and forms
  • Clear separation of concerns

This shift is foundational to modern Drupal architecture.

How Routing Fits with Other Core Systems

Routing works closely with:

  • Service container
  • Event dispatcher
  • Access API
  • Entity system
  • Cache system

Understanding routing makes these systems easier to understand.

Summary

The routing system is a core architectural layer that translates URLs into executable code. It is tightly integrated with dependency injection, access control, caching, and multilingual support. Mastering routing is essential for building clean, secure, and scalable Drupal 10 and 11 applications.

This article prepares you for deeper topics such as route subscribers, dynamic routes, event based routing, and REST routing.