Creating a custom module with routing and menu items in Drupal 8

Drupal 8 changes quite a bit when you go to create a custom module. This post will take us through setting up a module and adding a route and menu item. We are going to create a module that lets us track whether Game of Thrones characters are alive or dead, because it’s damn hard to keep track of them all!

1. Create a new directory for the module under the ‘modules’ directory. This is now in docroot, previously it was under sites/all. From docroot:

mkdir -p modules/custom/thrones

2. Inside the module directory, create a file called This is a YAML file, which is a data markup language that has been selected for use throughout Drupal 8. You can read more about it at

cd modules/custom/thrones

The yaml file should contain something like:

name: Thrones
type: module
description: 'Track the mortality of Game of Thrones characters.'
package: Custom
version: 1.0 
core: 8.x 
- node
configure: admin/structure/thrones/settings

Now create thrones.module and add the following:


* @file
* Allow users to manage the manage the mortality of Game of Thrones characters.

Great! A fully functional Drupal 8 module! Head to the Extend page and enable it. It will be under the Other category, or use the new search box to quickly locate it.

Head back to thrones.module and lets add the menu item. To do this we will need several things: a YAML file containing the routes (linking a URL to a controller), a hook_menu() to add the menu item and a controller class (very scary!).

Add the following to thrones.module:

 * Implements hook_menu().
function thrones_menu() {

  $items['admin/config/thrones'] = array(
    'title' => 'Settings',
    'access arguments' => array('administer thrones'),

 * Implements hook_permission().
function thrones_permission() {
  $permissions = array(
    'administer thrones' => array(
      'title' => t('Administer Thrones module'),
      'description' => t('Change the settings for thrones module.'),
 return $permissions;

Now create ‘thrones.routing.yml’ and add the following:

  pattern: '/admin/config/thrones'
    _content: '\Drupal\thrones\Controller\ThronesController::settings'
    _permission: 'administer thrones module'

Lastly, you need to create the controller. From the module’s root directory create the controller’s directory:

mkdir -p lib/Drupal/thrones/Controller

Inside the controller directory create the file ‘ThronesController.php’. This will contain your controller class, which should look like this:

 * @file
 * Contains \Drupal\thrones\ThronesController.

namespace Drupal\thrones\Controller;

use Symfony\Component\DependencyInjection\ContainerAware;

class ThronesController extends ContainerAware {

   * Administration page for thrones module.
  public function settings() {
    return 'Game of thrones is soo awesome!';

Now, head to admin/config/development/performance and clear the cache. Now navigate to admin/config/thrones and bask in the glory!

The Change record for the New Symfony Based Routing System has heaps more information on routes and what-not.

I’ll take this module further in future posts.




By Sam

Drupal developer from Perth, Western Australia. I love programming, gaming, the Internet, growing vegetables and hiking.


  1. Hi,

    Thx for the demonstration but for me it doesn’t work (testing in local)

    I’ve the error following :
    “Error message

    InvalidArgumentException: Class “\Drupal\thrones\Controller\ThronesController” does not exist. in Drupal\Core\Controller\ControllerResolver->createController() (line 80 of /home/XXX/workspace/XXX/core/lib/Drupal/Core/Controller/ControllerResolver.php).
    The website has encountered an error. Please try again later. ”

    Do you have a advise ?

  2. This post is currently out of date, I’ll update it once the PSR-4 patch goes through and the directory structure is stable.

Leave a comment

Your email address will not be published. Required fields are marked *