The render pipeline

Drupal 8

… while waiting for this talk to start, please already download

Thanks!   :)

The render pipeline

Drupal 8
Senior Software Engineer
Office of the CTO, Acquia

Our guide

Hah, you wish!

The Diagram

This is a map of Drupal 8!

with driving instructions!

In this talk, we're going to look at each area on the map.

…and at the end, you should feel like you understand Drupal 8!

Please download the PDF and follow along!

Without the driving instructions
Orientation points
The steps

Step 1: index.php

What is it?

  • Just like all previous Drupal versions!
  • What Symfony calls a front controller
    The front controller is a well-known design pattern; it is a section of code that all requests served by an application run through.
  • Symfony convention: app.php


  1. Create Symfony Request $request
  2. Create HttpKernel (initialize container, settings.php)
  3. $response = HttpKernel::handle($request)
  4. $response->prepare()
  5. $response->send()
  6. HttpKernel::terminate()

Should be familiar to any Symfony developer!

Step 2: HttpKernel::handle()

What is it?

  • Like an arbitrator: decides what happens
  • HttpKernel is the   ♥   of Symfony & Drupal!



  1. Event: REQUEST (negotiation + routing)
  2. Load Controller (_controller)
  3. Event: CONTROLLER (last second overriding)
  4. Get Controller arguments (introspection, parameter converters)
  5. Call the Controller
  6. If the result is a Response: all done! Otherwise…
  7. Event: VIEW (event subscriber must turn it into a Response)
  8. Event: RESPONSE (last second modifying)


  1. kernel.request
  2. kernel.controller
  3. kernel.view
  4. kernel.response

Anything is possible!

Step 3: events

What are they?

  • Most triggered by HttpKernel::handle()
  • The glue between Symfony and Drupal
  • Drupal can of course also trigger events, and does!

Step 4: Controller

What is it?

The application logic!

In Drupal 7: a page callback.

Determines the content of the response.


Return either:

  1. A Response object
  2. A render array
  3. An object
    (with associated VIEW event subscriber)


  1. Response: fully control what's sent (bye bye,   exit;  )
  2. Render array: let Drupal take care of sending
  3. Object: semantic data… >1 view subscribers can operate

    E.g.: a TabularData object: rendered as a CSV file response, or a HTML table, or a PDF file, or …

    E.g.: a LibraryBook object: rendered as a JSON response, or an image, or …

Step 5: MainContent ViewSubscriber

What is it?

View subscriber that handles (only!) render arrays

The render array-to-response arbitrator logic!


Selects & calls a main content renderer (~ negotiated format)


Another view subscriber could turn a "semantic data object" into a render array…

…and then have this view subscriber render it!

E.g.: a TabularData object: some view subscriber turns it into a
'#type' => 'table' render array.

Step 6: main content renderers

What are they?

The actual render array-to-response logic!

One "main content renderer"-tagged service per format.


  • Transform a render array into a Response
  • Drupal 8 already supports:
    • html text/html
    • ajax application/vnd.drupal-ajax
    • dialog application/vnd.drupal-dialog
    • modal application/vnd.drupal-modal


Add main content renderer services to support more formats!

Big picture

The Diagram

The steps

Step 7: the HTML main content renderer

Let's take a closer look at the most interesting part inside step 6!

What is it?

  • The most commonly used render array-to-response logic!
    (Because the web is all about HTML!)
  • Supports page display variants
    • Alternative methods of rendering main content
    • ⇒ alternative ways of filling page.html.twig
    • e.g.: Block, Panels, Page Manager…
  • Default: SimplePageVariant (just main content, no decoration)
  • Standard profile: BlockPageVariant (main content with blocks around it)


Fill page.html.twig's regions + render into Response

  1. Trigger the SELECT_PAGE_DISPLAY_VARIANT event
  2. Build selected page display variant (Simple, Block, PageManager …)
  3. drupal_render() everything!


  • Panels, Page Manager et cetera … without hacks!
  • Something none of us have even thought of yet?
  • A PartiallyDecapitatedPageVariant which:
    • lets Drupal render only the main content
    • uses JS + localStorage to render more dynamic/interactive alternatives to Blocks?

More about render arrays

Significantly improved rendering of render arrays in Drupal 8!

Too much for this talk, but will cover each in one slide:

  • Assets
  • Cache tags
  • Cache contexts
  • Bubbling
  • Render caching


Drupal 7:

Not in Drupal 8: asset dependencies!

See talk “Building really fast websites with Drupal 8”

Cache tags

“How to clear all cache items containing node 42?”


Cache tags!

// Associate the 'node:42' cache tag with the render array.
$node = Node::load(42);
$build['#cache']['tags'] = $node->getCacheTags();

// Automatically invalidates the 'node:42' cache tag!

See talks “Building really fast websites with Drupal 8” &
“Render caching in Drupal 7 and 8”

Cache contexts

Does the representation of the thing I'm rendering vary per permissions, per URL, per interface language, per … something?

Cache contexts!
(analogous to HTTP's Vary header)

// Associate the 'user.permissions' cache context with the render array.
if (\Drupal::currentUser()->hasPermission('pet llamas')) {
  $build['#markup'] = 'How many llamas will you pet today? :)';
$build['#cache']['contexts'][] = 'user.permissions';



Just like JavaScript events!

X-Drupal-Cache-Tags header: efficient Varnish purging!

See talk “Render caching in Drupal 7 and 8”

Render caching

Needs asset dependencies + cache tags/contexts + bubbling!

See talks “Building really fast websites with Drupal 8” &
“Render caching in Drupal 7 and 8”

(Also see my “renderviz: tool visualizing Drupal 8's render tree” project — ping me if you want to help!)

Hope you liked it!