Configuration

All Environment configuration options

9 min read 1752 words

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