Rendering a Block content using Lazy Builder callback in Drupal8

Speed is one of the most important performance issues for a site. By rendering the highly dynamic pages(poorly cacheable) the site becomes slow.

To improve the front-end performance of the site, Drupal8 uses rendering & caching system which provides us with a way to cache static part of the block and the dynamic one to be uncached. This is done by using the #lazy_builder callback to lazy load certain very dynamic subtrees of a render array. Lazy Builder, as the name suggests is used for lazy loading the site.

When a page is loaded, the static content is delivered to the page quickly using the cache. Whereas the dynamic content will be loaded slowly which is the reason for the poor performance of the site. But the #lazy_builder callback first assigns the dynamic part to a placeholder and the actual content is replaced when it is available.

When the #lazy_builder callback is encountered, the renderer replaces it with a placeholder.The placeholder contains information about which callback to call and the arguments to pass it. Then the placeholders are replaced with the complete content using Drupal’s default Single flush rendering strategy or by using Big Pipe module.

The example given below renders a Timestamp block and is displayed using the #lazy_builder callback. Let’s see how it works.


namespace Drupal\test\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;

 * @Block(
 *   id = "lazybuilder_block",
 *   admin_label = @Translation("Lazy Builder"),
 *   category = @Translation("Testing")
 * )
class LazyBuilderBlock extends BlockBase {
   * {@inheritdoc}
  public function build() {

    $content = [];
    $content['test'] = [
      '#lazy_builder' => [static::class . '::lazyBuildTestTable', array()],
      '#create_placeholder' => TRUE,
    $content['#markup'] = $this->t('Welcome!! ');
    return $content;

   * {@inheritdoc}
  public function blockForm($form, FormStateInterface $form_state) {
    $form = parent::blockForm($form, $form_state);
    return $form;

   * {@inheritdoc}
  public function blockSubmit($form, FormStateInterface $form_state) {


  public static function lazyBuildTestTable() {
    return array(
      '#markup' => date('d-m-Y h:i:s')



In the build() function, we have specified a key ‘#lazy_builder‘ which is an array. The first value contains the name of the callback and the second value is an array of arguments to pass to the callback.

We are using #markup for the cacheable part of the block plugin.

The callbacks can be of different formats:

  • A defined function:
'#lazy_builder' => ['test_lazy_buider', ['argument']];
  • Method on $this class: The one we used in the above code.
'#lazy_builder' => [static::class . '::lazybuildTestTable', ['argument']];
  • Method on any class:
'#lazy_builder' => [LazyBuilder::class . '::lazybuildTestTable', ['argument']];
  • A service:
'#lazy_builder' => ['', ['argument']];

Any number of arguments can be passed but all arguments must be primitive types.

The data is returned to the callback function and displayed in the block which is the dynamic part of the page. After enabling the BigPipe module you can observe the uncacheable content being rendered in the following way.


Only the static parts of the page are loaded from the cache, then the dynamic parts are rendered using LazyBuilder. By using this concept, you can achieve a perceived performance of the site.

About The Author

Leave a Reply