This project is not covered by Drupal’s security advisory policy.
Capabilities lets people assign one meaningful thing instead of many raw permissions. A capability is a named, translatable bundle of access, such as "Publish articles" or "Manage members of this project", that modules declare and site builders can define in the user interface.
It works in two places, on top of the access policy API that Drupal core introduced in 10.3:
- Site-wide. A capability can stand for the Drupal permissions one job needs. Instead of ticking ten checkboxes on the permissions page, you give a role or a user "Publish articles", and they get every permission that job needs.
- Within a scope. A capability can apply to one thing only, such as "edit project 7". Your module decides who holds it, for example from a membership table, and Drupal's access system does the rest. No role per project, no access checks scattered through controllers.
Features
- Capabilities declared by modules in
MODULE.capabilities.yml, the same way as permissions. - Capabilities defined by site builders in the UI, stored as configuration and exported with the rest of the site.
- Assignment to roles and directly to users.
implies: a capability can include others, so larger jobs build on smaller ones.- An overview page that answers "why can this person do this?": which capability grants which permission, and through which role or direct assignment.
- Scoped capabilities: a provider interface, an access policy, a resolver service and a
_scoped_capabilityroute requirement. - Correct cache metadata throughout, so access results cache safely.
Security
- Handing out capabilities requires its own permission, and nobody can assign a capability that grants permissions they do not hold themselves. This is enforced when the data is saved, not only in the forms.
- A capability that includes a restricted permission is marked as such wherever it can be assigned, as core does on the permissions page.
- Permissions that do not exist, for example from a module that is not installed, are never granted and are listed in the status report.
- Only declared capabilities can be granted. Unknown keys are dropped.
Declaring capabilities
Site-wide capabilities list the permissions they stand for:
content.review: scope: drupal label: 'Review articles' group: Content permissions: - 'access content overview' - 'view any unpublished content' content.publish: scope: drupal label: 'Publish articles' group: Content description: 'Write, edit and publish articles.' permissions: - 'create article content' - 'edit any article content' - 'use editorial transition publish' implies: [content.review]
Scoped capabilities name the scope they belong to:
project.view: scope: capabilities.project label: 'View the project' project.edit: scope: capabilities.project label: 'Edit project pages' implies: [project.view]
A list that cannot be written down in advance comes from a callback named under capability_callbacks: in the same file. hook_capabilities_info_alter() changes what other modules declare.
Checking access
On a route, with the identifier taken from a route parameter:
my_module.project_edit: path: '/project/{project}/edit' requirements: _scoped_capability: 'project.edit' options: capability_scope: capabilities.project capability_parameter: project
In code, the capabilities.resolver service returns an access result for one capability, or every capability in a scope mapped to true or false. Site-wide capabilities need no special checks: they grant ordinary Drupal permissions, so existing _permission requirements and hasPermission() calls keep working.
Requirements
- Drupal 11.3 or later
- PHP 8.3 or later
Installation
composer require drupal/capabilities drush en capabilities
Then give the right people the Administer capabilities and Assign capabilities permissions, and find the overview under People.
Project status
Under active development on the 1.0.x branch. The API may still change before the first stable release. Bug reports, ideas and patches are welcome in the issue queue.
Project information
- Project categories: Access control
- Created by vzsigmond on , updated
This project is not covered by the security advisory policy.
Use at your own risk! It may have publicly disclosed vulnerabilities.
Releases
First alpha release
Development version: 1.0.x-dev updated 14 Nov 2026 at 20:23 UTC

