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).
← Phase ④ HtmlRenderer calls Renderer::renderRoot()
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.
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.
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 ⑥ BigPipe3
#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 +
How they integrate with the render pipeline:
— A render array can use
— Twig templates can call
— The SDC system injects component CSS/JS as
— Unlike traditional theme hooks, SDC templates bypass
*.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
This final merged metadata is what gets attached to the
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