Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Twig Layouts (Template Inheritance)

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

To get a layout, add a new do something tag at the top of show.html.twig: extends 'base.html.twig':

{% extends 'base.html.twig' %}
<h1>The Genus {{ name }}</h1>
... lines 4 - 10

This says that we want base.html.twig to be our base template. But where does that file live? Remember: all templates live in app/Resources/views. And look, there's base.html.twig. This little file actually came with Symfony and it's your's to customize.

Refresh the browser after just this small change. Nice, a huge error

A template that extends another one can't have a body...

So what does that mean?

In Twig, layouts work via template inheritance. Ooooh. The base.html.twig template is filled with blocks:

<!DOCTYPE html>
<meta charset="UTF-8" />
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}

The job of the child template is to define content that should go into each of these blocks. For example, if you want your child template - show.html.twig in this case - to put content inside this body block, you need to override it. If you want to replace the title, then you'll override the title block.

Right now, our show.html.twig file is just barfing content. We're telling Twig we want to use base.html.twig, but it doesn't know where in that file this content should be placed.

To fix this, wrap all of the content in a block: {% block body %}. At the end, close it with {% endblock %}:

{% extends 'base.html.twig' %}
{% block body %}
<h1>The Genus {{ name }}</h1>
{% for note in notes %}
<li>{{ note }}</li>
{% endfor %}
{% endblock %}

Oh, and the names of these blocks are not important at all. You can change them to whatever you want and can add as many as you need.

The Web Debug Toolbar and Profiler

With this fixed up, head back to the browser and refresh. Cool! It's the same page, but now it has a full html source. Bonus time! Once you have a full html page, the web debug toolbar makes an appearance. This is a killer feature in Symfony: it includes information about which route was matched, which controller was executed, how fast the page loaded, who is logged in and more.

You can also click any of the icons to get even more detailed information in the profiler, including this amazing timeline that shows you exactly how long each part of your application took to render. This is amazing for debugging and profiling. There's also details in here on Twig, security, routes and other cool stuff. We'll keep exploring this as we go along.

Overriding a Second Block

Ok, the title of the page - "welcome" - well, that's not terribly inspiring or accurate for this page. That comes from the base layout, but it's wrapped in a block called title. Let's override that!

Add {% block title %}Genus {{ name }}{% endblock %}:

{% extends 'base.html.twig' %}
{% block title %}Genus {{ name }}{% endblock %}
... lines 4 - 13

The order of blocks doesn't matter: this could be above or below the body. Back to the browser and refresh! Ah ha! There's our new title -- not too shabby. That's it for Twig -- what's not to love?

Go Deeper!

If you want more, we have a whole screencast on just Twig templating engine: Twig Templating for Friendly Frontend Devs.

Leave a comment!

Login or Register to join the conversation
Default user avatar

dont work for me, and i have exactly that


Hey David,

What problem do you have? Do you can't inherit template?

Richard Avatar
Richard Avatar Richard | posted 5 years ago

It'd be quite nice to see some info on setting up a run config so we can also debug from php storm. I configured a built in php web server profile and it works and I can debug but I have to use a URL of the form http://localhost:8000/app_dev.php/genus/foobar/notes . Can anyone tell me how I can avoid the app_dev.php part? Some sort of "always run through this" option that I'm not seeing in the php options?


Hey Richard ,

Why are you try to avoid `app_dev.php` in URL? Anyway, it's some thing internal, only *you* should have access to this file and *only* on your localhost machine. So it's not a big deal to use it. But on production you should close this front controller, many devs just remove it at all from production server.

Btw, if you will run built in PHP web server via symfony console with `$ bin/console server:run` - it will load app_dev.php file by default, so you don't need to add /app_dev.php/ after your domain.


Default user avatar
Default user avatar Konrad Zając | posted 5 years ago

Why is the bar only in chrome, Safari desn't support it?


Hi Konrad!

You should totally see the web debug toolbar in ALL browsers, even Internet Explorer :p. However, the web debug toolbar doesn't show up until you have a full, valid HTML page. In other words, you won't see the web debug toolbar until you have valid <html>, <head>, and <body> tags. You *should* get this as soon as you extend the base.html.twig template.

However, if you don't see the web debug toolbar, view the HTML source on your page and make sure you have full valid HTML page markup. This is usually the reason why you won't see the web debug toolbar (Symfony purposefully only adds if when it sees full valid markup).


Default user avatar
Default user avatar Konrad Zając | weaverryan | posted 5 years ago

Ok, thanks!

Default user avatar

My site was in 'prod' - I switched it to 'dev' by changing web/.htaccess. Here I replaced app.php with app_dev.php
Did I change the environment by accident ? Is there an easy way to change the environment ?


Hi Klemens!

Ah, very clever! So ultimately, you "choose" the environment simply by executing app.php (prod) or app_dev.php (dev). But, there are 2 different ways of doing this usually:

1) Actually put app.php or app_dev.php in your URL - e.g. http://somehostname/app_dev.php/genus/octopus. Unless you're really misconfigured your web server, this will always work :).

2) Update your .htaccess file (or more generally, update your web server configuration - but for Apache, this is usually done in web/.htaccess) to load app_dev.php by default (i.e. when there is no filename in the URL). Then, when you go to http://somehostname/genus/octopus, it really executes app_dev.php, which loads Symfony in the dev environment. If you do this approach, you'll just want to make sure that you *don't* do after you deploy to production - you definitely want "app.php" to be executed when you're up on your server.

So you basically did option (2), which is completely valid :).


Default user avatar

Thanks for the quick answer! [besides: great tutorials !]

Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "composer/package-versions-deprecated": "^1.11" // 1.11.99
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0" // v3.1.3