render_block and Def Scope

Blocks do not inherit defs from the same template

1 min read 208 words

When you calltemplate.render_block("block_name", context), the block is rendered in isolation. It does not have access to {% def %}macros defined in the same template.

The Problem

{# page.html — def and block in same file #}
{% def helper() %}shared logic{% end %}

{% block content %}
  {{ helper() }}  {# NameError or UndefinedError when using render_block #}
{% end %}

If a framework (e.g. Chirp) calls template.render_block("content", ...), the block cannot see helperbecause blocks are compiled with their own scope.

Fix

Split defs into a separate file and import them:

{# _helpers.html #}
{% def helper() %}shared logic{% end %}
{# page.html #}
{% from "_helpers.html" import helper %}

{% block content %}
  {{ helper() }}
{% end %}

Now both full-page render() and render_block("content", ...) work, because the block imports helperfrom another template.

When This Matters

  • Fragment rendering — Chirp and similar frameworks userender_block()to return HTML fragments for htmx, SSE, etc.
  • Block caching — Site-scoped block caching renders blocks individually viarender_block().

See Also