rust-sailfish/sailfish

Simple, small, and extremely fast template engine for Rust

Rust

994

596 commits

updated Oct 13, 2026

See the code

README

SailFish

Simple, small, and extremely fast template engine for Rust

TestsVersiondependency statusRust 1.89License: MIT

User Guide | API Docs | Examples

✨ Features

  • Simple and intuitive syntax inspired by EJS
  • Include another template file inside template
  • Built-in filters
  • Minimal dependencies
  • Extremely fast (See benchmarks)
  • Better error message
  • Syntax highlighting support (vscode, vim)
  • Works on Rust 1.89 or later

🐟 Example

Dependencies:

[dependencies]
sailfish = "0.11.8"

You can choose to use TemplateSimple to access fields directly:

Template file (templates/hello.stpl):

<html>
  <body>
    <% for msg in messages { %>
      <div><%= msg %></div>
    <% } %>
  </body>
</html>

Code:

use sailfish::TemplateSimple;

#[derive(TemplateSimple)]
#[template(path = "hello.stpl")]
struct HelloTemplate {
    messages: Vec<String>
}

fn main() {
    let ctx = HelloTemplate {
        messages: vec![String::from("foo"), String::from("bar")],
    };
    println!("{}", ctx.render_once().unwrap());
}

Use Template to render through a shared reference and access fields and methods through self:

Template file (templates/hello.stpl):

<html>
  <body>
    <% for msg in &self.messages { %>
      <div><%= msg %></div>
    <% } %>
    <div><%= self.say_hello() %></div>
  </body>
</html>

Code:

use sailfish::Template;

#[derive(Template)]
#[template(path = "hello.stpl")]
struct HelloTemplate {
    messages: Vec<String>
}

impl HelloTemplate {
    fn say_hello(&self) -> String {
        String::from("Hello!")
    }
}

fn main() {
    let ctx = HelloTemplate {
        messages: vec![String::from("foo"), String::from("bar")],
    };
    println!("{}", ctx.render().unwrap());
}

You can find more examples in examples directory.

For mutable or consuming templates with access to self, use TemplateMut or TemplateOnce. See Choosing a template trait for a comparison of all four traits.

🐾 Roadmap

  • Template inheritance (block, partials, etc.)

👤 Author

🇯🇵 Ryohei Machida

🤝 Contributing

Contributions, issues and feature requests are welcome!

Since sailfish is an immature library, there are many planned features that is on a stage of RFC. Please leave a comment if you have an idea about its design!

Also I welcome any pull requests to improve sailfish! Find issues with Status: PR Welcome label, and let's create a new pull request!

Show your support

Give a ⭐️ if this project helped you!

📝 License

Copyright © 2020 Ryohei Machida.

This project is MIT licensed.


This README was generated with ❤️ by readme-md-generator

Documentation Deployment Instructions

sudo apt install mkdocs mkdocs-material
cd sailfish_root_folder &&
cd docs && cd en 
mkdocs build

rust
template-engine

rust-sailfish/sailfish

Simple, small, and extremely fast template engine for Rust

Rust

994

596 commits

updated Oct 13, 2026

See the code

README

SailFish

Simple, small, and extremely fast template engine for Rust

TestsVersiondependency statusRust 1.89License: MIT

User Guide | API Docs | Examples

✨ Features

  • Simple and intuitive syntax inspired by EJS
  • Include another template file inside template
  • Built-in filters
  • Minimal dependencies
  • Extremely fast (See benchmarks)
  • Better error message
  • Syntax highlighting support (vscode, vim)
  • Works on Rust 1.89 or later

🐟 Example

Dependencies:

[dependencies]
sailfish = "0.11.8"

You can choose to use TemplateSimple to access fields directly:

Template file (templates/hello.stpl):

<html>
  <body>
    <% for msg in messages { %>
      <div><%= msg %></div>
    <% } %>
  </body>
</html>

Code:

use sailfish::TemplateSimple;

#[derive(TemplateSimple)]
#[template(path = "hello.stpl")]
struct HelloTemplate {
    messages: Vec<String>
}

fn main() {
    let ctx = HelloTemplate {
        messages: vec![String::from("foo"), String::from("bar")],
    };
    println!("{}", ctx.render_once().unwrap());
}

Use Template to render through a shared reference and access fields and methods through self:

Template file (templates/hello.stpl):

<html>
  <body>
    <% for msg in &self.messages { %>
      <div><%= msg %></div>
    <% } %>
    <div><%= self.say_hello() %></div>
  </body>
</html>

Code:

use sailfish::Template;

#[derive(Template)]
#[template(path = "hello.stpl")]
struct HelloTemplate {
    messages: Vec<String>
}

impl HelloTemplate {
    fn say_hello(&self) -> String {
        String::from("Hello!")
    }
}

fn main() {
    let ctx = HelloTemplate {
        messages: vec![String::from("foo"), String::from("bar")],
    };
    println!("{}", ctx.render().unwrap());
}

You can find more examples in examples directory.

For mutable or consuming templates with access to self, use TemplateMut or TemplateOnce. See Choosing a template trait for a comparison of all four traits.

🐾 Roadmap

  • Template inheritance (block, partials, etc.)

👤 Author

🇯🇵 Ryohei Machida

🤝 Contributing

Contributions, issues and feature requests are welcome!

Since sailfish is an immature library, there are many planned features that is on a stage of RFC. Please leave a comment if you have an idea about its design!

Also I welcome any pull requests to improve sailfish! Find issues with Status: PR Welcome label, and let's create a new pull request!

Show your support

Give a ⭐️ if this project helped you!

📝 License

Copyright © 2020 Ryohei Machida.

This project is MIT licensed.


This README was generated with ❤️ by readme-md-generator

Documentation Deployment Instructions

sudo apt install mkdocs mkdocs-material
cd sailfish_root_folder &&
cd docs && cd en 
mkdocs build

rust
template-engine

Project health

crates.io

Latest release

0.11.8 · Sep 18, 2026

Releases this year

9

Significant stargazers

(top 24 of 35)

Markus Unterwaditzer

744 followers · starred Nov 2024

figsoda

283 followers · starred Dec 2020

Max Woolf

5,107 followers · starred Jun 2024

藍+85CD

258 followers · starred Jul 2023