Create custom twig templates from custom module

Last updated on
15 May 2017

The general idea in Drupal 8 is that you want to avoid creating html directly in the PHP code of your custom module. You want this to go into twig templates. To create new twig templates in your module, go through the following steps.

Step #1: Define hook_theme in .module file
Create a [module].module file if it doesn't already exist, and add code that defines each of your twig templates. The key of each item in the array is what you will need to call the template later. Do not use dashes in the file name.

function test_twig_theme($existing, $type, $theme, $path) {
  return [
    'my_template' => [
      'variables' => ['test_var' => NULL],

See the documentation for hook_theme().

Step #2: Call the Template
In the place where you are returning your render array (whether from a controller method that is called from your router yml file, or wherever), make a call to your twig template. Below is an example from a testing module that is called from the routing yml file in the module. (need more info on this part)

 * @file
 * Contains \Drupal\test_twig\Controller\TestTwigController.
namespace Drupal\test_twig\Controller;
use Drupal\Core\Controller\ControllerBase;
class TestTwigController extends ControllerBase {
  public function content() {
    return [
      '#theme' => 'my_template',
      '#test_var' => $this->t('Test Value'),

Keep in mind that this is a basic implementation, and doesn't do any kind of caching. The Render API Overview docs contain more information about how you can add caching to this. Speaking of caching - variable names will be cached and if you change them (say, "test_var" to "my_var") you'll have to refresh the cache.

Step #3: Create Twig Template
In your module, inside of the templates folder, create your twig template. The name of the file has to match what you put into hook_theme() (replace underscores with dashes). In this case, the file name would be my-template.html.twig.
Here is the file I used to test:

<p>Test twig template!</p>
<p>test_var: {{ test_var }}</p>

The beauty of this is that the template file defined in your module will be used if such a file does not already exist in your theme. Just dump a file inside of the /templates folder of your theme, clear cache (drush cr), and it will read that file instead. You can put the file in any nested sub-folder of the theme to keep things organized.