Django - The Easy Way Django - The Easy Way
Samuli Natri 2017.04.09
Samuli Natri is a software developer who enjoys programming games and web applications. He attended Helsinki University Of Technology (Computer Science) and Helsinki University (Social Sciences).

Drupal 8 - How To Create A Custom Module

Tutorial on how to create a simple module with Drupal 8.

Module Folder

Custom and contributed modules are placed in the /modules directory. You can use subdirectories so let’s create a subfolder /modules/custom and put the module there.

mkdir modules/custom
mkdir modules/custom/mymodule

In Drupal 7 /modules directory was reserved for core modules but in Drupal 8 it is used for custom and contributed modules. In Drupal 8 core modules goes to /core directory.

If you create /modules/contrib folder, then Drush will download modules there.

.Info file

.info file provides metadata that can be used elsewhere. It is required for Drupal to know about the module.

Create an info file modules/custom/mymodule/mymodule.info.yml with these lines:

name: My Module
description: A simple module.
package: Custom
type: module
core: 8.x

 Flush caches and you should see the module in /admin/modules:

It doesn’t do anything yet.


Create a routing file modules/custom/mymodule/mymodule.routing.yml with these lines:

  path: '/mymodule'
    _controller: '\Drupal\mymodule\Controller\MyModuleController::content'
    _permission: 'access content'

This invokes the content method we will define in MyModuleController.php.

 _controller value is not a path but a namespaced class defined by PSR standards.


Controller is used to execute the logic.

Create a folder for the controller:

mkdir modules/custom/mymodule/src
mkdir modules/custom/mymodule/src/Controller

A module has a namespace derived from its module name. For this it would be Drupal\mymodule. This is mapped to the /mymodule/src/ folder.

Create a controller file modules/custom/mymodule/src/Controller/MyModuleController.php with these lines:

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;

class MyModuleController extends ControllerBase {

   * Provide markup.
   * @return array
  public function content() {
    return array(
      '#type' => 'markup',
      '#markup' => t('My custom markup.'),

Enable the module and flush caches:

drush -y en mymodule
drush cr

Navigate to /mymodule and you should see this:

So the file:


is loaded and it's content method called because of the _controller value in the routing file:

_controller: '\Drupal\mymodule\Controller\MyModuleController::content'

.module File

You can also add a .module file for hooks:

Create a file modules/custom/mymodule/mymodule.module with these lines:

 * @file
 * Main hooks for MyModule module.

use Drupal\Core\Routing\RouteMatchInterface;

 * Implements hook_help().
function mymodule_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.mymodule':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Lorem ipsum. For more information, see the online <a href=":url">documentation</a>', array(
          ':url' => 'http://www.wdtutorials.com',
        )) . '</p>';
      return $output;

Flush caches.

This will provide a link to the help page:

Visit admin/help/mymodule to see the help page:

Folder Structure

The folder structure should now look like this: