Comparison with Other Template Engines
Waltzing takes a unique approach among Rust template engines, drawing inspiration from Scala's Twirl (Play Framework) rather than the more common Jinja2-style syntax.
Feature Comparison
| Feature | Waltzing | Askama | Tera | Maud | Sailfish |
|---|---|---|---|---|---|
| Compile-time | Yes | Yes | No (runtime) | Yes | Yes |
| Type-safe | Yes | Yes | No | Yes | Yes |
| Syntax style | Twirl (@) | Jinja2 ({{ }}) | Jinja2 | Rust macros | EJS (<% %>) |
| HTML-like components | Yes (<@component>) | No | No | No | No |
| Streaming output | Yes | No | No | No | Yes |
| Async output | Yes | No | No | No | No |
| Embedded JS/CSS/JSON | Yes (context-aware) | No | No | No | No |
| Default parameters | Yes | No | Yes | N/A | No |
| LSP support | Yes | Community | No | No | No |
| AI assistant tools | Yes (MCP server) | No | No | No | No |
Waltzing's Strengths
Function Tags
Compose components using familiar HTML-like syntax:
<@layout title="Home">
<@sidebar>
<@nav_item href="/" active />
</@sidebar>
<@main_content>
<h1>Welcome</h1>
</@main_content>
</@layout> This feels natural for anyone coming from React, Vue, or other component-based frameworks.
Embedded Languages
First-class support for Alpine.js, JavaScript, CSS, and JSON with proper escaping:
<div x-data=@```json {
userId: @user.id,
items: @items_json,
toggle() { this.open = !this.open; }
} ```@> The parser understands context and applies appropriate escaping rules.
Output Modes
Choose the right mode for your use case:
- Buffered - Simple, returns complete HTML
- Streaming - Memory efficient, writes incrementally
- Async - For async runtimes and streaming HTTP responses
Rust-Native Control Flow
Use actual Rust patterns, not a limited template DSL:
@if let Some(user) = current_user {
<span>Welcome, @user.name!</span>
}
@match status {
Status::Active => { <span class="green">Active</span> }
Status::Pending => { <span class="yellow">Pending</span> }
_ => { <span class="gray">Unknown</span> }
}Trade-offs
- Ecosystem size - Smaller community than Askama or Tera
- Learning curve - Different syntax if you're used to Jinja2-style templates
- Build setup - Requires CLI compiler in build.rs (vs Askama's derive macro)
When to Choose Waltzing
Waltzing is a great fit when you need:
- Component-based architecture with clean composition
- Alpine.js or HTMX integration with proper escaping
- Streaming or async template rendering
- Default parameter values for flexible components
- AI-assisted development with MCP server support
When to Choose Alternatives
- Askama - If you prefer Jinja2 syntax and derive macros
- Tera - If you need runtime template loading
- Maud - If you want pure Rust DSL without separate template files
- Sailfish - If you prefer EJS-style syntax and streaming