Blog/ Say Hello world to Drupal 8! [Basic steps involved in Creating a custom module in Drupal 8]

Compared to Drupal 7, there are few more steps involved in creating a custom module in Drupal 8. That's because Drupal 8 is using Symfony 2 components. Like Symfony, Drupal 8 code is object-oriented. 

Related Blog Posts


Here are the steps to create a custom module in Drupal 8:


Step 1: File Structure

In Drupal 8, we should keep the custom or contributed modules under modules folder in the root directory.


Note: For multisite configuration, you have to follow the file structure as described below for using modules specifically for each site.


Create "example" directory under "modules/custom" directory.

Step 2: Create .info.yml file

In Drupal 8, .info file changes to .info.yml. Old .info files have been converted to YAML and the .info parser has been removed. The new parser is the Symfony YAML component. The new file extension is .info.yml. This applies to modules, themes, and profiles.

Here is our file created under "examples" directory we created in Step 1.

name: Drupal 8 custom module example
type: module
description: 'Example for Drupal 8 modules.'
package: Custom
version: 8.x
core: 8.x

Step 3: Creating .routing.yml

First we have to write the path in .routing.yml file. In Drupal 8, we make heavy use of Symfony2 components to handle routing. This involves defining routes as configuration and handling the callback in a controller (the method of a Controller class). Here is our example.routing.yml file:

  path: '/mypage/page'
    _controller: '\Drupal\example\Controller\ExampleController::myPage'
    _title: 'My first page in Drupal8'
    _permission: 'access content'

The first line is the route [example.my_page]. Route is a symfony component, which maps an HTTP request to a set of configuration variables. In drupal8 route is defined as a machine name in the form of module_name.route_name, here is example.my_page {'module_name = example', 'route_name = my_page'}

Under path, we specify the path we want this route to register. This is the URL to the route, with a leading forward slash.

Under defaults, we have two things: the default page title (_title) and the _controller which references a method on the ExampleController class.

Under requirements, we specify the permission the accessing user needs to have to be able to view the page.

For more details about routing file you should consult this documentation.                      

Step 4: Create Route Controller Class

We have to create our ModuleController.php according to the PSR-4 naming standard. Create a folder "modules/custom/example/src/Controller". In this folder, create a file named "ExampleController.php" with the following content:

 * @file
 * @author Rakesh James
 * Contains \Drupal\example\Controller\ExampleController.
 * Please place this file under your example(module_root_folder)/src/Controller/
namespace Drupal\example\Controller;
 * Provides route responses for the Example module.
class ExampleController {
   * Returns a simple page.
   * @return array
   *   A simple renderable array.
  public function myPage() {
    $element = array(
      '#markup' => 'Hello world!',
    return $element;

Controller is a PHP function you create that takes information from the HTTP request and constructs and returns an HTTP response.

The controller contains whatever arbitrary logic your application needs to render the content of a page.The controller from the matched route is executed and the code inside the controller creates and returns a Response object.

Such as going to /mypage/page now executes the ExampleController::myPage() controller and render a page that simply prints Hello world!.

Step 5: Creating .module and hook_menu()

In Drupal 8, hook_menu() is used to define only menu items, not to define page callback functions as in Drupal 7. If we have hook_menu(), we need to make sure that the route and path in example.module should match exactly with the route and path which written in example.routing.yml. In our case, $items['/mypage/page'] in example.module is should be the same path: '/mypage/pagein example.routing.yml. Similarly the route 'route' => 'example.my_page' in example.module should be the same example.my_page: in example.routing.yml

Here is the content of the "example.module" file:

 * @File
 * Example custom module for Drupal 8.
 * @author Rakesh James

 * Implementing hook_menu().
function example_menu() {
  // The paths given here need to match the ones in example.routing.yml exactly.
  $items['/mypage/page'] = array(
    'title' => 'First page',
    'description' => 'This is a example page.',
    // The name of the route from example.routing.yml
    'route' => 'example.my_page',
  return $items;


Finally when you enable the module and go to /mypage/page URL, you'll see "Hello world!" text printed from our module. As you can see, creating custom module in Drupal 8 is little lengthier than Drupal 7. But it's really interesting and gives more versatility for customization. It will definitely take Drupal to higher level in software world. Here is the git repo for the example module in case you want to play around with it.

Related Blog Posts


Thank You Karthik for the information , When i am creating this module, hook_menu was to fully replaced like now.  

So whoever reading this article can skip the Step:5 and go to the Path "/mypage/page" You can see your "Hello World" printed on the page. 

I apologies for the late reply :)

By Paul (not verified) Thursday, May 28, 2015 - 02:17 Permalink

Was racking my mind trying to get it to work and finally came upon this blog showing _content needs to be _controller. Thanks!

By Uttam Kotekar (not verified) Sunday, June 21, 2015 - 23:44 Permalink

In .routing.yml file:

_permission: 'access content

_permission: 'access content'

By Drupal develop… (not verified) Tuesday, August 18, 2015 - 18:53 Permalink

Thanks for this writing! When young students ask me what and how to do with drupal I'm sending them to drupal blogs like yours!

By Nehal php (not verified) Monday, February 8, 2016 - 18:29 Permalink

Is the path '\Drupal\example\Controller\ExampleController::myPage', the directory structure ?
Because when running this complete module code as (localhost/drupal_8/mypage/page), I'm getting Page Not found Error . So, do I need to replace 'Drupal with drupal_8'

By Jeff (not verified) Saturday, February 27, 2016 - 12:22 Permalink

So to generate a page is it standard practice to change:
'#markup' => 'Hello world!',
'#markup' => $toPage,

Let $toPage accumlate the HTML needed to generate a page.

This is me experimenting with reading from a database.

It works. I didn't clean up the code... I just want to know if that is a correct standard.


Ready to get started?REQUEST A QUOTE