Skip to content

Drupal Template Suggestions — Fine-Grained Template Control

DodaTech Updated 2026-06-27 8 min read

In this tutorial, you'll learn how Drupal's template suggestion system works — how Drupal selects which template to use based on entity type, view mode, ID, and custom criteria, giving you fine-grained control over template rendering.

What You'll Learn

  • How Drupal discovers and selects templates using the suggestion system
  • Node, field, block, and page template suggestion patterns
  • Adding custom template suggestions via preprocess functions
  • Debugging template selection with Twig debug mode
  • Creating reusable suggestion patterns for custom entities

Why It Matters

By default, all nodes of all types use the same node.html.twig template. But in a real site, an Article needs a different layout than a Product or an Event. Template suggestions let Drupal propose multiple template filenames and use the first one that exists. This means you can have node--article.html.twig for articles, node--product.html.twig for products, and node--event.html.twig for events — all without complex PHP logic. Understanding the suggestion system is essential for building flexible, maintainable Drupal themes.

Real-World Use

A university website has four content types: News Article, Event, Course Listing, and Faculty Profile. Each needs a different layout. Using template suggestions, the theme creates one template per content type: node--news.html.twig, node--event.html.twig, node--course.html.twig, and node--faculty.html.twig. When a new content type is added later, the developer creates a new template file following the naming convention, and Drupal automatically uses it.

Learning Path

flowchart LR
  A[Sub-themes] --> B[Template Suggestions]
  B --> C[Asset Libraries]
  C --> D[Module Management]
  D --> E[Essential Modules]
  E --> F[Caching]
  F --> G[SEO]

What Are Template Suggestions?

When Drupal renders a piece of content, it does not immediately know which template file to use. Instead, it generates a list of possible template filenames, ordered from most specific to most general. Drupal then checks each filename in order and uses the first template file that exists in the theme.

Order of suggestion priority (most specific first):
node--article--full.html.twig
node--article.html.twig
node--full.html.twig
node.html.twig

If node--article--full.html.twig exists in the theme, Drupal uses it. If not, Drupal falls back to node--article.html.twig, and so on down to node.html.twig.

Node Template Suggestions

For nodes, Drupal generates suggestions based on content type, node ID, and view mode.

node.html.twig                              → Default (always available)
node--[type].html.twig                      → Content type specific
node--[type]--[view_mode].html.twig         → Content type + view mode
node--[nid].html.twig                       → Specific node ID
node--[nid]--[view_mode].html.twig          → Specific node + view mode

Example Suggestions for Node ID 42, Type "Article", View Mode "Full"

node--article--full.html.twig
node--article.html.twig
node--42--full.html.twig
node--42.html.twig
node--full.html.twig
node.html.twig

Example Suggestions for Teaser View Mode

node--article--teaser.html.twig
node--article.html.twig
node--42--teaser.html.twig
node--42.html.twig
node--teaser.html.twig
node.html.twig

Field Template Suggestions

Fields also have suggestions, organized by field name, entity type, and bundle.

field.html.twig                                     → Default
field--[field_name].html.twig                       → Specific field name
field--[entity_type]--[field_name].html.twig        → Entity type + field name
field--[entity_type]--[bundle]--[field_name].html.twig  → Full specificity

Example for the "body" Field on Article Content Type

field--node--article--body.html.twig
field--node--body.html.twig
field--body.html.twig
field.html.twig

This lets you style the body field differently on articles vs events, or render the image field differently from the text field.

Block Template Suggestions

Blocks generate suggestions based on the block plugin ID and the block's custom ID.

block.html.twig                                → Default
block--[plugin_id].html.twig                   → Block type
block--[region].html.twig                      → Region placement
block--[plugin_id]--[region].html.twig         → Block type + region
block--[block_id].html.twig                    → Specific block

Example for the "system_branding_block" in the Header Region

block--system-branding-block--header.html.twig
block--system-branding-block.html.twig
block--header.html.twig
block.html.twig

Page Template Suggestions

The page template generates suggestions based on the route path.

page.html.twig                              → Default
page--[path].html.twig                      → Specific path
page--[section].html.twig                   → Path section
Example for path /articles/2026/drupal-tutorial:
page--articles--2026--drupal-tutorial.html.twig
page--articles--2026.html.twig
page--articles.html.twig
page.html.twig

For the front page:

page--front.html.twig
page.html.twig

Region Template Suggestions

Regions have simple suggestions based on the region machine name.

region.html.twig                → Default
region--[region].html.twig      → Specific region
{# Example: region--sidebar.html.twig #}
<aside class="region-sidebar">
  {{ content }}
</aside>

Adding Custom Suggestions via Preprocess

You can add custom template suggestions using preprocess functions in your .theme file.

<?php
// mytheme.theme

/**
 * Implements hook_preprocess_HOOK() for node templates.
 */
function mytheme_preprocess_node(&$variables) {
  $node = $variables['node'];
  
  // Add a suggestion based on a field value.
  if ($node->hasField('field_featured') && $node->field_featured->value) {
    $variables['theme_hook_suggestions'][] = 'node__featured';
  }
  
  // Add a suggestion based on the author role.
  $author = $node->getOwner();
  if ($author->hasRole('editor')) {
    $variables['theme_hook_suggestions'][] = 'node__editor';
  }
  
  // Add a suggestion based on page section (using taxonomy).
  if ($node->hasField('field_section') && !$node->field_section->isEmpty()) {
    $section = $node->field_section->entity;
    $variables['theme_hook_suggestions'][] = 'node__section__' . $section->getMachineName();
  }
}

For Drupal 10+ (using the #suggestions array):

<?php
function mytheme_preprocess_node(&$variables) {
  $node = $variables['node'];
  
  // Add suggestion array for modern Drupal.
  if ($node->hasField('field_section') && !$node->field_section->isEmpty()) {
    $section = $node->field_section->entity;
    $variables['suggestions'][] = 'node__section__' . $section->getMachineName();
  }
}

Using hook_theme_suggestions_alter

For module-level control, use the alter hook:

<?php
/**
 * Implements hook_theme_suggestions_alter().
 */
function mymodule_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if ($hook === 'node') {
    $node = $variables['elements']['#node'];
    
    // Add a suggestion for nodes created by administrators.
    if ($node->getOwner()->id() === 1) {
      $suggestions[] = 'node__admin_created';
    }
    
    // Remove default suggestions for specific content types.
    if ($node->bundle() === 'secret') {
      $suggestions = array_filter($suggestions, function($suggestion) {
        return strpos($suggestion, 'node__teaser') === false;
      });
    }
  }
}

Hook for Specific Entity Types

<?php
/**
 * Implements hook_theme_suggestions_node_alter().
 */
function mymodule_theme_suggestions_node_alter(array &$suggestions, array $variables) {
  $node = $variables['elements']['#node'];
  
  // Add suggestion for nodes that are part of a campaign.
  if ($node->hasField('field_campaign') && !$node->field_campaign->isEmpty()) {
    $campaign = $node->field_campaign->entity;
    if ($campaign) {
      $suggestions[] = 'node__campaign__' . $campaign->id();
    }
  }
}

Debugging Template Selection

Enable Twig debugging to see which suggestions are available and which template was selected.

Enable Debug Mode

# sites/default/services.yml
parameters:
  twig.config:
    debug: true

View in HTML Source

After enabling, view the page source. Drupal adds HTML comments showing the suggestion list:

<!-- THEME HOOK: 'node' -->
<!-- FILE NAME SUGGESTIONS:
   * node--article--full.html.twig
   * node--article.html.twig
   * node--full.html.twig
   x node.html.twig
-->
<!-- BEGIN OUTPUT from 'themes/custom/mytheme/templates/node.html.twig' -->

The x marks which template was selected. Unused suggestions have *.

<!-- THEME HOOK: 'field' -->
<!-- FILE NAME SUGGESTIONS:
   x field--node--article--body.html.twig
   * field--node--body.html.twig
   * field--body.html.twig
   * field.html.twig
-->
<!-- BEGIN OUTPUT from 'themes/custom/mytheme/templates/field--node--article--body.html.twig' -->

Theme Hook Suggestions

Theme hooks are Drupal's internal names for renderable elements. Each theme hook follows the same suggestion pattern.

<?php
// Example: adding suggestions for a custom theme hook.
function mytheme_theme_suggestions_my_custom_hook_alter(array &$suggestions, array $variables) {
  // Add a suggestion based on a parameter.
  if (!empty($variables['type'])) {
    $suggestions[] = 'my_custom_hook__' . $variables['type'];
  }
}

Common Theme Hook Examples

Theme hook:               Suggestions:
menu                      menu--main.html.twig, menu--footer.html.twig
breadcrumb                breadcrumb.html.twig
pager                     pager.html.twig
table                     table.html.twig
status_messages           status-messages.html.twig
links                     links.html.twig

Suggestion Patterns for Custom Entities

If you create a custom entity type, you can define suggestion patterns:

<?php
/**
 * Implements hook_theme_suggestions_HOOK() for a custom entity.
 */
function mymodule_theme_suggestions_product(array $variables) {
  $suggestions = [];
  $entity = $variables['elements']['#product'];
  
  $suggestions[] = 'product__' . $entity->bundle();
  $suggestions[] = 'product__' . $entity->id();
  
  if (!empty($variables['view_mode'])) {
    $suggestions[] = 'product__' . $entity->bundle() . '__' . $variables['view_mode'];
  }
  
  return $suggestions;
}

Common Mistakes

  1. Using wrong filename naming: Template suggestions use double underscores __, not hyphens. node--article.html.twig is correct; node-article.html.twig is ignored.

  2. Not clearing cache after adding templates: Drupal caches the template discovery. Run drush cr after adding new template files.

  3. Creating overly specific suggestions: node--123.html.twig for a single node is rarely useful. Use content type suggestions for broader coverage.

  4. Forgetting view mode in suggestions: A template for node--article.html.twig works for both full page and teaser. Use node--article--full.html.twig when you need view mode specificity.

  5. Not using Twig debug to verify suggestions: Guessing which template is being used leads to wasted time. Enable Twig debug and check the HTML source comments.

Practice Questions

  1. How does Drupal determine which template to use when rendering a node? List the suggestion order for node 42 of type Article in full view mode.

  2. What is the difference between hook_preprocess_HOOK() and hook_theme_suggestions_alter() for adding custom template suggestions?

  3. How would you create a template suggestion that applies only to the "body" field on the "Article" content type when shown in the "teaser" view mode?

  4. Challenge: Design a template suggestion Strategy for a job board site with content types Job Listing, Company Profile, and Application. Define the template files you would create for each content type, including view mode variants. Write a preprocess function that adds a 'featured' suggestion for job listings marked as sponsored.

FAQ

What are template suggestions in Drupal?

Template suggestions are alternative template filenames that Drupal checks when rendering content. They follow naming conventions like node--article.html.twig and allow different templates for different content types, view modes, or specific entities.

How do I see which template is being used?

Enable Twig debugging in sites/default/services.yml by setting twig.config.debug: true. View the HTML source of the page and look for HTML comments showing THEME HOOK and FILE NAME SUGGESTIONS.

What is the naming convention for template suggestions?

Use double underscores between parts: node--article--full.html.twig. Hyphens in the middle of a part are fine (field--field-name.html.twig), but the separators between parts must be double underscores.

Can I add template suggestions from a custom module?

Yes, use hook_theme_suggestions_HOOK_alter() or hook_theme_suggestions_alter() in your custom module to add or remove suggestions for any theme hook.

How do I create a template for a specific content type?

Create a file named node--[type].html.twig in your theme's templates directory, replacing [type] with the machine name of the content type. For example, node--article.html.twig for the Article content type.

Mini Project

Goal: Create template suggestions for a multi-content-type site.

  1. Enable Twig debugging in services.yml
  2. Create four node template files:
    • node--article.html.twig with a newspaper-style layout
    • node--product.html.twig with a product card layout
    • node--event.html.twig with a date-highlighted layout
    • node.html.twig as the default fallback
  3. Create field--node--article--body.html.twig to style the body field differently for articles
  4. Create block--system-branding-block--header.html.twig for the branding block in header
  5. Add a preprocess function that adds a "promoted" suggestion for sticky nodes
  6. Verify each template is used correctly using the Twig debug HTML comments

What's Next

Now that you understand template suggestions, proceed to asset libraries to manage CSS and JavaScript. After that, explore module management to install and update contributed modules.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro