Backend Development – Custom Modules

A custom module is the primary way backend behavior is added to a Drupal site. While configuration controls how content is structured and displayed, custom modules define how Drupal behaves, how data flows, and how systems integrate.

In simple terms, custom modules are where Drupal stops being just a CMS and starts acting like a full backend framework.

This article is the first article in the Level 2 – Backend Development series. It sets the foundation for everything that follows, including routing, controllers, forms, AJAX, entities, queues, cron jobs, and Drush commands.

Rather than learning concepts in isolation, this series follows a learning‑by‑building approach. We will create and extend a real custom module step by step. Each new backend topic builds on the same module, so concepts connect naturally and mirror real project work.

By the end of Level 2, you will not just understand backend APIs, you will understand how Drupal backend architecture fits together as a system.


1. Why Custom Modules Are the Entry Point to Backend Drupal

Drupal backend development starts when configuration is not enough.

As soon as you need to:

  • Control logic
  • Fetch or store custom data
  • Integrate external systems
  • Build workflows

You need a custom module.

A custom module is how you tell Drupal what new behavior exists and when it should run.


2. Where Custom Modules Live

All custom modules live here:

/web/modules/custom/

Example:

/web/modules/custom/weeklydrupal_demo/

Drupal automatically scans this directory and discovers modules.


3. The Minimum Required File: *.info.yml

Every Drupal module must have an .info.yml file. Without it, Drupal will not recognize the module.

Example: weeklydrupal_demo.info.yml

name: WeeklyDrupal Demo
type: module
description: Demonstrates backend concepts for WeeklyDrupal
core_version_requirement: ^9 || ^10
package: WeeklyDrupal

4. Required vs Optional Keys in info.yml

Required keys

KeyPurpose
nameHuman-readable name shown in admin UI
typeMust be module
core_version_requirementDefines compatible Drupal core versions

If any of these are missing, Drupal will not load the module.

Common optional keys

KeyPurpose
descriptionExplains what the module does
packageGroups modules in admin UI
dependenciesEnsures other modules are enabled first

Example with dependencies:

dependencies:
  - drupal:node
  - drupal:user

5. What Happens When Drupal Reads info.yml

When you enable a module:

  1. Drupal reads the info.yml file
  2. Registers the module internally
  3. Makes it available for routing, services, hooks, and plugins

At this stage, no PHP code has executed yet.


6. Adding PHP Code: The .module File

The .module file is optional but commonly used.

Purpose:

  • Implements hooks
  • Acts as an integration layer

Example: weeklydrupal_demo.module

<?php

use Drupal\Core\Routing\RouteMatchInterface;

/**
 * Implements hook_help().
 */
function weeklydrupal_demo_help($route_name, RouteMatchInterface $route_match) {
  if ($route_name === 'help.page.weeklydrupal_demo') {
    return '<p>This module demonstrates backend Drupal concepts.</p>';
  }
}

Explanation

  • Function name starts with the module name
  • Drupal calls this function automatically at the correct time
  • Your code does not decide when to run; Drupal does

7. Introducing Routing (Backend Entry Point)

Backend logic usually starts with a route.

weeklydrupal_demo.routing.yml

weeklydrupal_demo.page:
  path: '/weeklydrupal/demo'
  defaults:
    _controller: '\Drupal\weeklydrupal_demo\Controller\DemoController::page'
    _title: 'WeeklyDrupal Demo'
  requirements:
    _permission: 'access content'

8. How Drupal Finds the Controller Class

The controller definition:

_controller: '\Drupal\weeklydrupal_demo\Controller\DemoController::page'

Means:

  • Drupal\weeklydrupal_demo matches the module name
  • Controller is a folder under src/
  • DemoController is the PHP class
  • page is the method Drupal calls

Drupal uses PSR-4 autoloading to locate the file.


9. Controller File Explained

File path

weeklydrupal_demo/src/Controller/DemoController.php

Code

<?php

namespace Drupal\weeklydrupal_demo\Controller;

use Drupal\Core\Controller\ControllerBase;

class DemoController extends ControllerBase {

  public function page() {
    return [
      '#markup' => $this->t('Hello from WeeklyDrupal backend module'),
    ];
  }

}

Explanation

  • Namespace maps to folder structure
  • ControllerBase provides Drupal helpers
  • Method returns a render array, not HTML

Drupal converts the render array into HTML.


10. Why Controllers Should Stay Thin

Controllers should:

  • Handle requests
  • Call services
  • Return render arrays

Controllers should not:

  • Contain business logic
  • Query databases
  • Call external APIs

That work belongs in services.


11. Introducing Services (Backend Logic Layer)

Services hold reusable backend logic.

weeklydrupal_demo.services.yml

services:
  weeklydrupal_demo.message_generator:
    class: Drupal\weeklydrupal_demo\Service\MessageGenerator

Service class

<?php

namespace Drupal\weeklydrupal_demo\Service;

class MessageGenerator {

  public function getMessage(): string {
    return 'This message comes from a backend service.';
  }

}

12. Injecting the Service into the Controller

use Drupal\weeklydrupal_demo\Service\MessageGenerator;

class DemoController extends ControllerBase {

  protected MessageGenerator $generator;

  public function __construct(MessageGenerator $generator) {
    $this->generator = $generator;
  }

  public static function create($container) {
    return new static(
      $container->get('weeklydrupal_demo.message_generator')
    );
  }

  public function page() {
    return [
      '#markup' => $this->generator->getMessage(),
    ];
  }
}

Explanation

  • Drupal's service container creates the service
  • The controller does not build dependencies itself
  • This pattern is called dependency injection

13. Learning by Building: WeeklyDrupal Demo Module

Throughout Level 2, we will extend this same module.

Planned additions:

  • Custom routes
  • Forms and validation
  • AJAX interactions
  • Queue and batch processing
  • Cron jobs
  • Drush commands

Each topic builds on the previous one using real code.


14. Why This Topic Comes First

Every backend feature in Drupal depends on custom modules.

If you understand this topic well:

  • Routes make sense
  • Forms feel structured
  • Services feel natural
  • Architecture decisions become clear

This is the foundation of Backend Development.