Understanding and using Drupal's hook systemfor Drupal 8 , 9 , 10 , and 11

Last updated :  

Think of a Drupal site as a shared office building where every module rents a floor. Core doesn't know, and shouldn't need to know, what any individual tenant module wants to do when a new employee logs in, a page renders, or a form gets submitted. Instead, at each of those key moments, core walks down the hallway and knocks on every module's door with a specific, predictable question — "does anyone want to do something here?" That knock is a hook, and the entire architecture that makes Drupal extensible without ever touching core code depends on it.

What you'll learn in this lesson

  • What a hook actually is, and why the naming convention hook_NAME() exists
  • The three parts every hook has: a name, an implementation, and a definition
  • How Drupal discovers your hook implementations automatically — and the one thing you must remember to do after adding a new one
  • A first, working hook implementation you can add to any module right now

A hook is just a function with a predictable name

If your module is machine-named example_module and you want to react to a user logging in, you write a function named exactly example_module_user_login(). That's it — no registration file, no service definition, no annotation. Drupal's own documentation defines the abstract hook as hook_user_login(), and implementing it is simply a matter of replacing the literal word hook with your own module's machine name.

/**
 * Implements hook_user_login().
 */
function example_module_user_login(array $edit, \Drupal\user\UserInterface $account) {
  \Drupal::logger('example_module')->notice('User %name has logged in.', [
    '%name' => $account->getAccountName(),
  ]);
}

The moment this function exists, in an enabled module, Drupal will call it every single time any user logs in — anywhere on the site, triggered by any code, including core's own login form or a contributed module's SSO integration. You never call this function yourself.

The three parts of a hook

Every hook in Drupal breaks down into exactly three pieces, and keeping them distinct will save you a lot of confusion later:

  • The name — the abstract pattern like hook_user_login, documented (often in a module's .api.php file) so other developers know it exists and what arguments it receives.
  • An implementation — your module's concrete function, named with your module's machine name instead of the literal word hook.
  • A definition — the code, somewhere, that actually triggers the hook and collects the results. For core hooks this lives deep in Drupal core; for a hook your own module defines, you write this part yourself using the module_handler service.
Where hooks fit architecturally: this pattern is what lets dozens of unrelated, independently-authored modules all react to the same event — a node being saved, a form being built, a user logging in — without any of them knowing the others exist, and without a single line of core code ever needing to change to support a new module next year.

Discovery is cached — remember to clear it

Drupal doesn't scan your codebase on every request looking for functions matching a naming pattern — that would be far too slow. Instead, the list of which modules implement which hooks is built once and cached. This means that the very first time you add a brand-new hook implementation to a module, Drupal won't call it until you clear the cache (drush cr, or Configuration → Performance → Clear all caches). Forgetting this step is one of the most common "why isn't my hook running?" moments for developers new to Drupal.

Quick check: you've just added hooks_example_user_login() to a module and enabled it, but logging in produces no log message. Before assuming your code is wrong, what's the first thing to try? (Answer: clear the cache. Drupal's hook-implementation list is cached and only rebuilds when the cache is cleared or a module is installed/uninstalled — a brand-new implementation on an already-enabled module won't be picked up until then.)

Key takeaways

  • A hook implementation is a plain function named <your_module_name>_<hook_name>() — no registration step beyond the function existing.
  • Every hook has three distinct parts: the documented name, your concrete implementation, and the definition that actually invokes it.
  • Hook discovery is cached — always clear the cache after adding your module's first implementation of a given hook.
  • You never call your own hook implementation directly; Drupal (or whichever module defined the hook) calls it for you at the right moment.

Coming up next

Knowing a hook will run is only half the story — sometimes you need to control which order multiple modules' implementations run in, or exclude one entirely. Next up: Creating hook_module_implements_alter, which hands you exactly that control.