How to programmatically print a webform block with caching enabled? When displaying a Webform inside a normal block (using admin/structure/block) Drupal manage to correctly cache the page, the HTTP header displays X-Drupal-Dynamic-Cache: HIT.
However we need to display this webform inside a paragraph so we tried the following :

use twig_tweak module and {{ drupal_block('webform_...') }}
programmatically put the block in a template preprocess like this :

$my_form = \Drupal\webform\Entity\Webform::load('contact_new');
$output = \Drupal::entityManager()
          -&gt;getViewBuilder('webform')
          -&gt;view($my_form);
$variables['contact_form'] = $output;

Both solutions seem to make the page uncacheable: X-Drupal-Dynamic-Cache: UNCACHEABLE.
What would be the correct way to put a block in a paragraph while make the page cacheable ?
How to mimic the standard block system to display a in our template ?
The Dynamic Page Cache needs to placeholder the dynamic part and it can only do so when it is built in a lazy builder:
/mymodule/src/WebformLazyBuilder.php
&lt;?php

namespace Drupal\mymodule;

use Drupal\Core\Render\Element\RenderCallbackInterface;

class WebformLazyBuilder implements RenderCallbackInterface {

  public static function buildWebform($webform) {
    return  [
      'webform' =&gt; [
        '#type' =&gt; 'webform',
        '#webform' =&gt; $webform,
      ],
    ];
  }

}

Then you can put the lazy builder in a template preprocess hook:
$variables['contact_form'] =  [
  '#lazy_builder' =&gt; ['\Drupal\mymodule\WebformLazyBuilder::buildWebform', ['contact']],
  '#create_placeholder' =&gt; TRUE,
];

Blocks are placed in a lazy builder by default, see BlockViewBuilder::viewMultiple.