Drupal Template Suggestions — Fine-Grained Template Control
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
Using wrong filename naming: Template suggestions use double underscores
__, not hyphens.node--article.html.twigis correct;node-article.html.twigis ignored.Not clearing cache after adding templates: Drupal caches the template discovery. Run
drush crafter adding new template files.Creating overly specific suggestions:
node--123.html.twigfor a single node is rarely useful. Use content type suggestions for broader coverage.Forgetting view mode in suggestions: A template for
node--article.html.twigworks for both full page and teaser. Usenode--article--full.html.twigwhen you need view mode specificity.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
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.
What is the difference between
hook_preprocess_HOOK()andhook_theme_suggestions_alter()for adding custom template suggestions?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?
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
Mini Project
Goal: Create template suggestions for a multi-content-type site.
- Enable Twig debugging in services.yml
- Create four node template files:
node--article.html.twigwith a newspaper-style layoutnode--product.html.twigwith a product card layoutnode--event.html.twigwith a date-highlighted layoutnode.html.twigas the default fallback
- Create
field--node--article--body.html.twigto style the body field differently for articles - Create
block--system-branding-block--header.html.twigfor the branding block in header - Add a preprocess function that adds a "promoted" suggestion for sticky nodes
- 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