askama
Use when writing Askama templates in Rust to ensure idiomatic patterns, fix compile errors by understanding module scope, and avoid common anti-patterns from Jinja2 muscle memory
SKILL.md
| Name | askama |
| Description | Use when writing Askama templates in Rust to ensure idiomatic patterns, fix compile errors by understanding module scope, and avoid common anti-patterns from Jinja2 muscle memory |
name: askama description: Use when writing Askama templates in Rust to ensure idiomatic patterns, fix compile errors by understanding module scope, and avoid common anti-patterns from Jinja2 muscle memory
Askama Templates in Rust
Overview
Askama templates are Rust code compiled at build time. Templates share the module scope where #[derive(Template)] appears — everything visible there is usable in the template.
Quick Reference - What to Load
| If you're... | Load |
|---|---|
| Learning Askama syntax, conditionals, loops, match | references/template-syntax.md |
| Seeing "method not found" or "type not found" errors | references/scope-debugging.md |
| Tempted to convert a type to String to fix an error | references/scope-debugging.md |
Using or creating filters, the safe filter | references/filters.md |
| Using template extends, blocks, includes | references/inheritance.md |
| Rendering HTML fragments for HTMX hx-swap | references/htmx-partials.md |
Error Message → Reference
| If you see... | Load |
|---|---|
"method not found in [TypeName]" | references/scope-debugging.md |
"cannot find type [TypeName] in this scope" | references/scope-debugging.md |
| "trait bound not satisfied" in template context | references/scope-debugging.md |
| Unexpected whitespace in output | references/template-syntax.md (whitespace control) |
Core Principles
Templates Are Rust Code: Askama templates compile to Rust. Use Rust idioms: call methods on types, leverage Display implementations, pattern match with {% match %}. Don't pre-compute strings in Rust when the template can call the method directly.
Module Scope Determines Visibility: The template can only access what's visible in the module where #[derive(Template)] appears. If a method isn't found, the trait providing it isn't imported — fix the imports, don't convert to String.
Keep Rich Types: Pass domain types to templates, not stringified versions. A template receiving EventStatus can call .css_class(), .display_name(), and match on variants. A template receiving a String can only display it.
Compile-Time Safety: Template errors surface at cargo build, not at runtime. This is a feature. Don't fight it by converting everything to strings — embrace it by fixing scope issues properly.
Validate Before Rendering: The safe filter bypasses escaping. Only use it for content you control (pre-rendered HTML from your own code). Never use it on user input.
STOP — Anti-Rationalization Table
Before writing code that matches these patterns, STOP and reconsider.
| You're about to... | Common rationalization | What to do instead |
|---|---|---|
| Convert a type to String to fix "method not found" | "It's faster than fixing the scope" / "I'll clean it up later" | Import the trait in the template's module. The 20 minutes you spent is sunk cost — don't compound it. Load references/scope-debugging.md. |
Use {% elif %} (Jinja2 syntax) | "It's more familiar" / "Team uses Python too" | Use {% else if %}. Askama is Rust, not Jinja2. The compile error is telling you this. |
Apply safe filter to user-controlled data | "It's already validated server-side" / "We trust this field" | Never trust, always escape. If you need HTML, render it through a controlled template, not {{ raw_html | safe }}. Load references/filters.md. |
Skip using {% match %} for an enum | "If/else is simpler" | Match is exhaustive — the compiler catches forgotten variants. If/else silently ignores new cases. |
| Pre-format everything in Rust before passing to template | "Templates should just display" | Templates can call methods. Keep logic in types, let templates use it. |
| Add imports inside a macro file or think macros have their own scope | "The macro needs its own imports" / "It works in the other template" | Askama macros share the scope of the calling Template struct's module. Import traits there. Load references/scope-debugging.md. |
Suppress dead_code on Template struct fields | "The template uses it but Rust doesn't see it" | Wrong — Rust does see it. Askama's derive macro generates code that reads every field the template uses, including through macros. If dead_code fires, the field is genuinely unused. Delete it. |
Authoritative Resources
- Askama Book — Official documentation
- Askama Template Syntax — Syntax reference
- Askama Filters — Built-in and custom filters
- askama on docs.rs — API documentation