Understanding Drupal's Render API
Render arrays are Drupal’s structured description of output. Their real power is not the final HTML; it is the metadata that lets Drupal compose, vary, invalidate, and progressively deliver that output correctly.
Markup plus metadata
A render array can describe theme hooks, children, libraries, placeholders, and caching. Cache contexts answer “what varies?”, tags answer “what invalidates?”, and max-age answers “how long?”. Missing metadata can produce either stale output or needless cache misses.
Lazy builders isolate expensive variation
A lazy builder defers a small fragment and gives Drupal the opportunity to placeholder it. BigPipe can send the stable page shell first and replace personalized or slow fragments later.
The callable must return a render array and receive only scalar arguments. Keep it deterministic and attach the same cacheability the direct build would have required.
Bubbleability is the contract
Cacheability and asset attachments bubble from children to parents. Avoid rendering early into strings because doing so discards that composition model. Return render arrays until Drupal’s main renderer owns the final conversion.
Working example
return [
'#lazy_builder' => ['portfolio.user_summary:build', [$account_id]],
'#create_placeholder' => TRUE,
'#cache' => [
'contexts' => ['user'],
'tags' => ['user:' . $account_id],
],
];The three cache dimensions solve different problems
Cache contexts describe variation. If output differs by route, language, permissions, theme, or another request property, the cache entry needs the corresponding context. Cache tags describe dependencies. If a rendered fragment depends on a node, configuration object, taxonomy term, or list of entities, tags allow Drupal to invalidate that output when the dependency changes. Max-age describes time-based reuse and whether the result can be cached at all.
These values are not interchangeable. Setting a low max-age does not correct a missing context, and clearing every cache does not correct a missing tag. Cache metadata is part of the correctness of the render array.
Rendering too early breaks composition
One of the easiest mistakes is converting a child render array to a string because a caller wants markup. That can detach the child from the metadata bubbling that Drupal's renderer performs. Attached libraries, cache tags, cache contexts, and placeholders all need an opportunity to travel upward through the render tree.
Returning structured render arrays until the normal page renderer takes ownership preserves those relationships. This is especially important for reusable components that may appear inside blocks, Views, controllers, or other render elements.
Debug the render array before the HTML
When output is stale, unstyled, or unexpectedly personalized, inspect the structure that produced it. Look at #cache, #attached, theme hooks, children, and lazy builders before focusing only on the final markup. A browser can show that a library is missing; the render array can explain why it was never attached.
Key Takeaways
- Cache contexts, tags, and max-age solve different problems.
- Use lazy builders for small, expensive, highly variable fragments.
- Do not flatten render arrays before Drupal can bubble metadata.