All Environment configuration options.
Environment Constructor
from kida import Environment, FileSystemLoader
env = Environment(
loader=FileSystemLoader("templates/"),
autoescape=True,
auto_reload=True,
cache_size=400,
fragment_cache_size=1000,
fragment_ttl=300.0,
)
Core Options
loader
Template source provider.
| Type | Default | Description |
|---|---|---|
Loader | None |
None |
Template loader |
# FileSystemLoader
loader = FileSystemLoader("templates/")
# Multiple paths
loader = FileSystemLoader(["templates/", "shared/"])
# DictLoader
loader = DictLoader({"page.html": "..."})
autoescape
Escaping mode for output.
| Type | Default | Description |
|---|---|---|
bool | "html" | "terminal" | "markdown" | Callable |
True |
Select escaping behavior |
# Always escape
autoescape=True
# Never escape
autoescape=False
# Terminal ANSI-safe escaping
autoescape="terminal"
# GitHub-flavored Markdown escaping
autoescape="markdown"
# Conditional by filename
def should_escape(name):
if name is None:
return True
return name.endswith((".html", ".xml"))
autoescape=should_escape
Markdown mode is for generated Markdown such as GitHub step summaries, PR comments, and release notes. It escapes CommonMark/GFM formatting triggers while keeping ordinary punctuation readable. Since 0.9.0, inline hyphens, parentheses, hashes, pipes, and tildes are not escaped unless they appear where Markdown treats them as block markers. Values marked with | safe or Markup(...) bypass Markdown escaping through __markdown__, so only mark trusted Markdown safe.
auto_reload
Check for template source changes.
| Type | Default | Description |
|---|---|---|
bool |
True |
Check on each load |
# Development: check for changes
auto_reload=True
# Production: skip checks
auto_reload=False
Cache Options
cache_size
Maximum compiled templates to cache.
| Type | Default | Description |
|---|---|---|
int |
400 |
LRU cache size |
# Small cache (testing)
cache_size=10
# Large cache (production)
cache_size=1000
fragment_cache_size
Maximum{% cache %}fragments to cache.
| Type | Default | Description |
|---|---|---|
int |
1000 |
Fragment cache size |
fragment_ttl
Fragment cache time-to-live in seconds.
| Type | Default | Description |
|---|---|---|
float |
300.0 |
5 minutes |
# Short TTL for development
fragment_ttl=1.0
# Longer TTL for production
fragment_ttl=3600.0 # 1 hour
fragment_ttl is the default for {% cache %}blocks. You can override TTL per block:
{% cache "user-" ~ user.id, ttl="5m" %}
{{ render_profile(user) }}
{% end %}
Supported ttlformats in templates:
- Numeric seconds (
ttl=30,ttl=0.5) - Duration strings (
"30s","5m","2h","1d")
bytecode_cache
Persistent bytecode cache for cold-start performance.
| Type | Default | Description |
|---|---|---|
BytecodeCache | bool | None |
None |
Bytecode cache |
from kida.bytecode_cache import BytecodeCache
# Auto-detect (default)
bytecode_cache=None
# Explicit disable
bytecode_cache=False
# Custom location
bytecode_cache=BytecodeCache("__pycache__/kida/")
Bytecode cache files are trusted application state. Store them in an application-owned directory, not a shared or user-writable location: cache files contain marshalled code and serialized compiler data, and the sandbox does not treat bytecode cache contents as untrusted input.
static_context
Static values for partial evaluation at compile time. Expressions that depend only on these values are evaluated during compilation and replaced with constants in the bytecode — enabling near-str.format() speed for static regions (e.g. site.title, config.base_url).
| Type | Default | Description |
|---|---|---|
dict[str, Any] | None |
None |
Values known at compile time |
# Site-wide config available in all templates
env = Environment(
loader=FileSystemLoader("templates/"),
static_context={"site": site_config, "config": app_config},
)
# from_string() accepts its own static_context kwarg (takes precedence)
template = env.from_string("{{ site.title }}", static_context={"site": {"title": "My Site"}})
Applied automatically to all templates loaded via get_template(). Use from_string(source, static_context={...})to override per-call.
Lexer Options
Control template syntax delimiters.
block_start / block_end
Tag delimiters.
| Option | Default | Description |
|---|---|---|
block_start |
"{%" |
Opening tag |
block_end |
"%}" |
Closing tag |
variable_start / variable_end
Output delimiters.
| Option | Default | Description |
|---|---|---|
variable_start |
"{{" |
Opening output |
variable_end |
"}}" |
Closing output |
comment_start / comment_end
Comment delimiters.
| Option | Default | Description |
|---|---|---|
comment_start |
"{#" |
Opening comment |
comment_end |
"#}" |
Closing comment |
Custom Delimiters
# Ruby-like syntax
env = Environment(
block_start="<%",
block_end="%>",
variable_start="<%=",
variable_end="%>",
comment_start="<%#",
comment_end="%>",
)
Whitespace Options
trim_blocks
Remove newline after block tags.
| Type | Default | Description |
|---|---|---|
bool |
False |
Trim after%} |
lstrip_blocks
Remove leading whitespace before block tags.
| Type | Default | Description |
|---|---|---|
bool |
False |
Strip before{% |
env = Environment(
trim_blocks=True,
lstrip_blocks=True,
)
Behavior Options
strict_none
Strict None comparison in sorting.
| Type | Default | Description |
|---|---|---|
bool |
False |
Fail on None comparisons |
# Lenient (default): None sorts last
strict_none=False
# Strict: raise error on None
strict_none=True
strict_undefined
Strict attribute access — raiseUndefinedError on missing attributes instead of returning the _Undefinedsentinel.
| Type | Default | Description |
|---|---|---|
bool |
True |
Raise on missing attributes |
# Strict (default): missing attributes raise UndefinedError immediately
strict_undefined=True
# Lenient: missing attributes return the _Undefined sentinel (renders as "")
strict_undefined=False
By default, {{ user.typo }} raises immediately instead of rendering as empty string — the same contract as undefined top-level variables. Error messages distinguish between "Undefined variable", "Undefined attribute", and "Undefined key", and include did you mean …suggestions.
To keep the lenient behavior on a specificEnvironment (useful when migrating templates that rely on optional attributes), pass strict_undefined=False. The preferred in-template idioms for optional data are:
{{ user.bio ?? "" }}— null-coalescing{% if user.bio is defined and user.bio %}— existence guard{{ user.bio | default("") }}— filter with fallback
jinja2_compat_warnings
EmitMigrationWarning when a nested {% set %} shadows a name already bound template-wide via {% let %} or {% export %}— the Jinja2 scoping trap.
| Type | Default | Description |
|---|---|---|
bool |
True |
Warn on nested{% set %}that shadows a template-scope binding |
# Default — catches the Jinja2 trap
jinja2_compat_warnings=True
# Silence the warning entirely
jinja2_compat_warnings=False
# Or filter via stdlib warnings:
# warnings.filterwarnings("ignore", category=MigrationWarning)
When enabled, a template like {% let x = 1 %}{% if cond %}{% set x = 2 %}{% end %} emits a MigrationWarning (K-WARN-002) — in Jinja2 the author would expect x == 2 after the block, but Kida's block-scoped {% set %} leaves x == 1. The warning names the shadowed variable and suggests {% export %}as the fix.
The warning is narrowly scoped to the actual trap pattern: fresh names used for genuine block-scoped purposes (e.g., a loop-local counter) do not trigger — Kida and Jinja2 behave identically there.
fstring_coalescing
Enable f-string output coalescing optimization.
| Type | Default | Description |
|---|---|---|
bool |
True |
Coalesce consecutive outputs into f-strings |
When enabled, the compiler merges consecutive output nodes (static text and simple expressions) into single f-string appends, reducing function call overhead by ~37% in output-heavy templates.
# Enabled (default) — recommended for production
fstring_coalescing=True
# Disable for debugging compiled output
fstring_coalescing=False
See Compiler Internals for details on how coalescing works.
pure_filters
Additional filters the compiler can treat as side-effect-free.
| Type | Default | Description |
|---|---|---|
set[str] |
set() |
Custom pure filter names |
Filters in this set are assumed to have no side effects and can be coalesced into f-strings alongside built-in pure filters (escape, upper, lower, trim, default, etc.). When static_contextis provided, pure filters with fully static inputs are evaluated at compile time and replaced with constants.
# Manual registration via configuration
pure_filters={"markdown", "highlight", "currency"}
The preferred approach is the @pure decorator, which auto-registers filters as pure when added via add_filter():
from kida import Environment, pure
@pure
def currency(value, symbol="$"):
return f"{symbol}{value:,.2f}"
env = Environment()
env.add_filter("currency", currency)
# "currency" is automatically added to pure_filters
validate_calls
Enable compile-time call-site validation for{% def %}functions.
| Type | Default | Description |
|---|---|---|
bool |
False |
Validate call sites against{% def %}signatures |
When enabled, the compiler checks every{{ func(...) }} call against the matching {% def %} signature and emits UserWarningfor unknown parameters, missing required arguments, and other mismatches. Duplicate keyword arguments are rejected by the parser before validation runs.
# Enable call validation (recommended for development/CI)
validate_calls=True
# Disabled (default) — no validation overhead
validate_calls=False
See Static Analysis — Call-Site Validation for programmatic API details.
preserve_ast
Preserve AST for template introspection.
| Type | Default | Description |
|---|---|---|
bool |
True |
Keep AST after compile |
# Enable introspection (default)
preserve_ast=True
# Disable to save memory
preserve_ast=False
max_extends_depth / max_include_depth
Resource limits for DoS protection. Configurable for deployments with deep template hierarchies.
| Option | Type | Default | Description |
|---|---|---|---|
max_extends_depth |
int |
50 |
Maximum{% extends %}chain depth |
max_include_depth |
int |
50 |
Maximum{% include %} / {% embed %}depth |
# Deeper inheritance for complex sites
env = Environment(
max_extends_depth=100,
max_include_depth=75,
)
Exceeding these limits raises TemplateRuntimeError. See Security Hardening for details.
enable_htmx_helpers
Register HTMX helper globals (hx_request, hx_target, hx_trigger, hx_boosted, csrf_token).
| Type | Default | Description |
|---|---|---|
bool |
True |
Enable HTMX helpers |
When enabled, templates can usehx_request(), hx_target(), etc. Frameworks must set metadata via render_context().set_meta()before rendering. See Custom Globals for HTMX helper details.
Development vs Production
Development
env = Environment(
loader=FileSystemLoader("templates/"),
autoescape=True,
auto_reload=True, # Check for changes
cache_size=50, # Small cache
fragment_ttl=1.0, # Short TTL
)
Production
env = Environment(
loader=FileSystemLoader("templates/"),
autoescape=True,
auto_reload=False, # No reload checks
cache_size=1000, # Large cache
fragment_ttl=3600.0, # 1 hour TTL
)
Cache Methods
cache_info()
Get cache statistics.
info = env.cache_info()
print(info["template"])
# {'size': 5, 'max_size': 400, 'hits': 100, 'misses': 5, 'hit_rate': 0.95}
clear_cache(include_bytecode=False)
Clear all caches.
env.clear_cache() # Memory only
env.clear_cache(include_bytecode=True) # Include disk
clear_template_cache(names=None)
Clear specific templates.
env.clear_template_cache() # All
env.clear_template_cache(["base.html", "page.html"]) # Specific
clear_fragment_cache()
Clear fragment cache only.
env.clear_fragment_cache()
See Also
- API Reference — Environment methods
- Loading Templates — Loader configuration
- Performance — Optimization tips