BlogHow to use handlebars template in Rust?

In this article, we will explore the powerful capabilities of Handlebars templates and how to harness their potential within Rust. By combining the flexibility of Handlebars with the efficiency of Rust, you'll be equipped to create dynamic and elegant templates for your projects. Let's dive in and discover how to seamlessly integrate Handlebars templates into your Rust applications.

Let's start by installing the handlebars crate in your Rust project by running the command cargo add handlebars. We will also include serde_json so that we can pass a JSON to our template as data. Once that is installed, we can try a very basic example.

use handlebars::Handlebars;
use serde_json::json;

fn main() {
    let handlebars = Handlebars::new();

    let result = handlebars
        .render_template(
            "Hello, {{name}}!",
            &json!({
                "name": "world"
            }),
        )
        .unwrap();

    println!("{}", result);
}

You can now run the example and you should see:

Hello, world!

Let's go through the important bits:

  • let handlebars = Handlebars::new();: Here, a new instance of the Handlebars struct is created. This instance represents the Handlebars template engine and is used to render templates.
  • let result = handlebars ...;: In this line, the render_template method of the Handlebars instance is called. It takes two arguments:
    • The first argument is the template string: "Hello, {{name}}!". This is a Handlebars template with a placeholder {{name}} that will be replaced with actual data during rendering.
    • The second argument is the data to be used in the template rendering. In this case, the json!() macro is used to create a JSON object: &json!({ "name": "world" }). This JSON object has a key-value pair "name": "world", where "name" corresponds to the placeholder {{name}} in the template.

That was pretty straightforward and easy right? We can easily render template and also make use of several build-in helpers to handle conditional logic, loops and more. We can even add our own custom helper that can manipulate data or handle custom rendering logic. Here is an example:

use handlebars::Handlebars;
use handlebars::{Context, Helper, HelperDef, HelperResult, Output, RenderContext};
use serde_json::json;

#[derive(Clone, Copy)]
pub struct StringifyHelper;

impl HelperDef for StringifyHelper {
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper,
        _: &Handlebars,
        _: &Context,
        _: &mut RenderContext,
        out: &mut dyn Output,
    ) -> HelperResult {
        let param = h.param(0).map(|v| v.value()).expect("Expected parameter");
        out.write(serde_json::value::Value::to_string(param).as_str())?;
        Ok(())
    }
}

fn main() {
    let mut handlebars = Handlebars::new();
    handlebars.register_helper("stringify", Box::new(StringifyHelper));

    let result = handlebars
        .render_template(
            "Hello, {{name}}! {{stringify obj}}",
            &json!({
                "name": "world",
                "obj": {
                    "a": 1,
                    "b": 2,
                }
            }),
        )
        .unwrap();

    println!("{}", result);
}

We've now added a new custom Handlebars helper called StringifyHelper is added to handle stringify JSON. Additionally, this helper is registered with the Handlebars instance (which has to mutable now), and the template now includes a new {{stringify obj}} expression to demonstrate the helper's usage.

When we run this code we can see:

Hello, world! {"a":1,"b":2}

If you want to see an even more advanced example for transforming data, you can checkout some of the helpers defined in this open-source static site generator: RustyInk.

I hope this guide lets you get started with handlebars in Rust.

Start free trial

Effortlessly create compelling changelogs and seamlessly deliver product updates with our no-code changelog tool.

Get Started