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