Minimizing hook_* implementations for speedfor Drupal 11 , 10 , 9 , and 8

Last updated :  

A hook implementation runs on every request that triggers its event, for every enabled module that implements it — a slow hook_page_attachments() or a heavy hook_entity_view() pays its cost on literally every applicable page load, whether or not that specific page actually needed what the hook does. Minimizing hook overhead isn't about avoiding hooks entirely; it's about making sure each one does the least possible work before deciding it has nothing to do.

What you'll learn in this lesson

  • Why hook discovery itself has a real, if small, cost
  • The "bail out early" pattern that keeps a hook cheap on the common case
  • When a dynamic hook variant is the actual performance fix

Bail out before doing real work

function mymodule_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  // Bad: checks the condition AFTER already doing expensive setup.
  // $data = _mymodule_expensive_lookup($entity);
  // if ($entity->bundle() !== 'article') { return; }

  // Good: the cheapest possible check happens first, before anything costly.
  if ($entity->getEntityTypeId() !== 'node' || $entity->bundle() !== 'article') {
    return;
  }

  $data = _mymodule_expensive_lookup($entity);
  // ... use $data ...
}

This hook fires for every entity view, of every entity type, on the site. Ordering the cheap, disqualifying check first means the vast majority of invocations (every non-article entity) return almost instantly, and the genuinely expensive lookup only runs for the small subset of calls that actually need it.

Reach for the dynamic hook variant when it exists

// Instead of the generic hook_entity_view() with a manual type check...
function mymodule_node_view(array &$build, NodeInterface $node, EntityViewDisplayInterface $display, $view_mode) {
  // ... this dynamic variant only ever fires for nodes at all —
  // Drupal's own dispatch mechanism does the filtering, not your code.
}
Why this is more than just cleaner code: the generic hook_entity_view() genuinely invokes your function for every entity type — users, files, taxonomy terms, everything — meaning your function call overhead happens even for entity types you immediately bail out of. The dynamic hook_ENTITY_TYPE_view() variant is filtered by Drupal's own module handler before your code ever runs, which is strictly cheaper than filtering inside a generic hook yourself.

Hook discovery itself has a cost

Drupal caches the list of which modules implement which hooks (that's what hook_module_implements_alter(), from the Module Development tutorial, lets you influence) — but that list still has to be iterated on every triggering event. A site with many modules each implementing the same commonly-fired hook (like hook_form_alter(), which fires for every single form on the site) pays a small dispatch cost per implementation, on top of whatever each implementation actually does.

Quick check: your module only cares about articles, but implements the generic hook_entity_view() and checks the bundle inside. Would switching to hook_node_view() (still generic across node types) or hook_ENTITY_TYPE_view() targeted specifically at articles be strictly cheaper? If you said yes to the more targeted variant, you've understood that Drupal's own pre-filtering beats a manual check inside a broader hook.

Key takeaways

  • Order the cheapest, most disqualifying check first in any frequently-fired hook — expensive work only after confirming it's actually needed.
  • Prefer dynamic hook variants (hook_ENTITY_TYPE_view(), hook_form_FORM_ID_alter()) over generic ones when they exist — Drupal's own dispatch does the filtering, which is cheaper than doing it yourself inside the hook body.
  • A hook implemented by many modules (like hook_form_alter()) has a real cumulative dispatch cost even before any individual implementation's own logic runs.

Coming up next

Hooks run eagerly whenever their event fires. Next, we look at services — and how to make sure an expensive service only actually gets constructed when something genuinely needs it.