Defining Route Requirements in Drupal: Access Rules and Constraintsfor Drupal 8 , 9 , 10 , and 11

Last updated :  

Every route needs a requirements block — it's not optional, and Drupal refuses to even register a route without one. Think of it as the bouncer at the door: before your controller ever runs, Drupal checks whatever rule you've written here, and only lets the request through if it passes. This lesson covers the different kinds of requirements you can write, from the simplest permission check to constraining what a URL placeholder is even allowed to contain.

What you'll learn in this lesson

  • The simplest possible requirement: _access: 'TRUE'
  • Gating a route behind a named permission with _permission
  • Constraining a placeholder's format directly in requirements

The simplest requirement: wide open access

page_example.description:
  path: '/examples/page-example'
  defaults:
    _controller: '\Drupal\page_example\Controller\PageExampleController::description'
    _title: 'Page Example'
  requirements:
    _permission: 'access content'

Here, _permission: 'access content' means: any user who holds the "access content" permission (which anonymous visitors have by default on most sites) can view this page. This is the most common requirement you'll write — checking a single named permission.

Truly public routes

requirements:
  _access: 'TRUE'

Set this instead when you genuinely want no access restriction at all — not even a permission check. Reach for this sparingly; it's easy to forget a route is wide open until something sensitive ends up behind it by accident.

Constraining a placeholder's value

Requirements aren't only about permissions — you can also constrain what a URL placeholder is allowed to look like, using a regular expression:

my_module.item:
  path: '/my-module/item/{id}'
  defaults:
    _controller: '\Drupal\my_module\Controller\MyController::view'
  requirements:
    _permission: 'access content'
    id: \d+

Adding id: \d+ means this route only matches when {id} is one or more digits — a request for /my-module/item/abc won't match this route at all (Drupal falls through to a 404, or to another route if one exists), so your controller never even has to defensively check whether $id is numeric.

Gotcha: a regex requirement filters which requests match the route in the first place — it's not the same as validating input inside your controller. If the constraint is wrong or missing, malformed input reaches your PHP code directly, so treat this as your first line of defense, not your only one.

Quick check: you add id: \d+ to a route's requirements. A visitor requests the path with a non-numeric value in that slot. What does Drupal do? It doesn't run your controller and throw an error inside it — the route simply doesn't match at all, so Drupal falls back to a 404 (or another matching route) before your code ever executes.

Key takeaways

  • requirements is mandatory on every route — Drupal won't register a route without at least one entry.
  • _permission: 'name' is the most common requirement, gating access behind a specific permission string.
  • _access: 'TRUE' makes a route fully public with no permission check at all — use it deliberately, not by default.
  • A placeholder can be constrained with a regular expression directly in requirements, filtering which URLs match before your controller ever runs.

Coming up next

Beyond simple string and regex constraints, Drupal can do something more powerful with a placeholder: automatically load a full entity object from an ID in the URL. The next lesson, Setting Route Parameters, shows you how.