D11 Pipeline: Renderer Theme

Phase ⑤

Renderer & Theme System

The Renderer service recursively processes a render array tree — checking caches, invoking pre/post render callbacks, calling the theme system, and writing Twig to HTML. In Drupal 11 the theme layer also supports Single Directory Components (SDC).

 
Renderer Service — Entry Point
Renderer::renderRoot() / Renderer::render()
Drupal\Core\Render\Renderer (formerly the drupal_render() procedural function).
Recursively traverses the render array tree. For each element:
1
Render cache lookup
If #cache keys are defined, check cache.render bin. Cache ID derived from keys + resolved contexts.
Cache HIT
Return cached markup immediately.
Bubble cache metadata (tags, contexts, max-age) up to parent element.
Skip steps 2–8 for this element.
Cache MISS — render continues ↓
Proceed with full rendering pipeline.
Collect cache metadata as rendering progresses.
Write to cache after step 8.
2
#lazy_builder / auto-placeholder check
If #lazy_builder is set, or auto-placeholder conditions are met (max-age=0, user context, session context), replace element with a placeholder. The actual render is deferred. → see Phase ⑥ BigPipe
3
#pre_render callbacks
Callables in #pre_render may modify the element before it reaches the theme system. Commonly used to compute values, alter structure, or add #attached assets dynamically.
4
Recurse into children
For each child element (keys without # prefix), call render() recursively. Children are rendered before the parent's theme output is produced.
5
ThemeManager::render() — Theme system + Twig
Calls theme() with the negotiated hook. Applies template suggestions, preprocess hooks (hook_preprocess_HOOK()), then renders the Twig template. Detail below ↓
6
#post_render callbacks
Callables in #post_render receive the rendered HTML string (#children) and may alter it. Rare — prefer #pre_render where possible.
7
Prepend/append #prefix and #suffix
Raw HTML strings from #prefix and #suffix are concatenated around #children.
8
Write render cache + bubble metadata
Store result in cache.render bin (with resolved cache tags, contexts, max-age). Bubble cache metadata up to the parent element so the parent's cache entry includes all child dependencies.
 
Theme System — Step 5 Detail
ThemeManager → Hook Negotiation → Preprocess → Twig
The theme system resolves which template to use, prepares variables via preprocess hooks, then delegates to the Twig renderer.
1. Theme hook negotiation
Collects template suggestions (from hook_theme_suggestions_HOOK() and template_preprocess). Picks most-specific match in active theme.
2. Preprocess hooks
template_preprocess()template_preprocess_HOOK()MODULE_preprocess_HOOK()THEME_preprocess_HOOK(). Variables are built up and added to the template context.
3a. Twig template render
Twig engine compiles .html.twig template (cached in cache.default as PHP). Executes with the preprocessed variables. Returns HTML string.
3b. SDC component render (D11)
If render element uses #type component or Twig calls {% include 'theme:button' %}, the SDC system handles prop/slot injection and its own Twig template. See below.
Single Directory Components (SDC) — Drupal 11 core
SDC are self-contained UI component bundles (Twig template + *.component.yml + CSS/JS), living in a components/ directory within any module or theme.

How they integrate with the render pipeline:
— A render array can use '#type' => 'component' with '#component' => 'theme:button' to render an SDC from PHP.
— Twig templates can call {% include 'theme:button' with {label: 'Click'} %}.
— The SDC system injects component CSS/JS as #attached libraries automatically — no manual hook_theme() registration needed.
— Unlike traditional theme hooks, SDC templates bypass hook_preprocess_HOOK() for the component itself — props/slots are the explicit API.
 
Cache Metadata Bubbling
BubbleableMetadata propagation up the tree
As each element renders, its cache tags, contexts, and max-age are merged upward.
The root element (the #type html array) accumulates all cache metadata from every child.
This final merged metadata is what gets attached to the HtmlResponse as X-Drupal-Cache-Tags and X-Drupal-Cache-Contexts headers.
cache tags
cache contexts
max-age
merged upward per element
added to HtmlResponse headers
used by Dynamic Page Cache
 
→ Phase ⑥ Caching & BigPipe / HtmlResponse

Next: Phase ⑥ Caching & BigPipe →