fiji-flo
gtmpl-rust
Rust

golang text/template for rust

Last updated Mar 15, 2026
91
Stars
12
Forks
8
Issues
0
Stars/day
Attention Score
16
Language breakdown
No language data available.
β–Έ Files click to expand
README

gtmpl-rust – Golang Templates for Rust

[![Latest Version]][crates.io]

[Latest Version]: https://img.shields.io/crates/v/gtmpl.svg [crates.io]: https://crates.io/crates/gtmpl


[gtmpl-rust] provides the [Golang text/template] engine for Rust. This enables seamless integration of Rust application into the world of devops tools around [kubernetes], [docker] and whatnot.

Getting Started

Add the following dependency to your Cargo manifest…

[dependencies] gtmpl = "0.7"

and look at the docs:

It's not perfect, yet. Help and feedback is more than welcome.

Some Examples

Basic template:

use gtmpl;

fn main() { let output = gtmpl::template("Finally! Some {{ . }} for Rust", "gtmpl"); assert_eq!(&output.unwrap(), "Finally! Some gtmpl for Rust"); }

Adding custom functions:

use gtmpl_value::Function; use gtmpl::{FuncError, gtmpl_fn, template, Value};

fn main() { gtmpl_fn!( fn add(a: u64, b: u64) -> Result<u64, FuncError> { Ok(a + b) }); let equal = template(r#"{{ call . 1 2 }}"#, Value::Function(Function { f: add })); assert_eq!(&equal.unwrap(), "3"); }

Passing a struct as context:

use gtmpl_derive::Gtmpl;

#[derive(Gtmpl)] struct Foo { bar: u8 }

fn main() { let foo = Foo { bar: 42 }; let output = gtmpl::template("The answer is: {{ .bar }}", foo); assert_eq!(&output.unwrap(), "The answer is: 42"); }

Invoking a method on a context:

use gtmpl_derive::Gtmpl; use gtmpl::{Func, FuncError, Value};

fn plus_one(args: &[Value]) -> Result<Value, FuncError> { if let Value::Object(ref o) = &args[0] { if let Some(Value::Number(ref n)) = o.get("num") { if let Some(i) = n.as_i64() { return Ok((i +1).into()) } } } Err(anyhow!("integer required, got: {:?}", args)) }

#[derive(Gtmpl)] struct AddMe { num: u8, plus_one: Func }

fn main() { let addme = AddMe { num: 42, plusone }; let output = gtmpl::template("The answer is: {{ .plusone }}", addme); assert_eq!(&output.unwrap(), "The answer is: 43"); }

Current Limitations

This is work in progress. Currently the following features are not supported:

  • complex numbers
  • the following functions have not been implemented:
* html, js printf is not yet fully stable, but should support all sane* input

Enhancements

Even though it was never intended to extend the syntax of Golang text/template there might be some convenient additions:

Dynamic Template

Enable gtmpldynamictemplate in your Cargo.toml:

[dependencies.gtmpl] version = "0.7" features = ["gtmpldynamictemplate"]

Now you can have dynamic template names for the template action.

Example

use gtmpl::{Context, Template};

fn main() { let mut template = Template::default(); template .parse( r#" {{- define "tmpl1"}} some {{ end -}} {{- define "tmpl2"}} some other {{ end -}} there is {{- template (.) -}} template "#, ) .unwrap();

let context = Context::from("tmpl2");

let output = template.render(&context); asserteq!(output.unwrap(), "there is some other template".tostring()); }

The following syntax is used:

{{template (pipeline)}} 	The template with the name evaluated from the pipeline (parenthesized) is     executed with nil data.

{{template (pipeline) pipeline}} The template with the name evaluated from the first pipeline (parenthesized) is executed with dot set to the value of the second pipeline.

Context

We use [gtmplvalue]'s Value as internal data type. [gtmplderive] provides a handy derive macro to generate the From implementation for Value.

See:

Why do we need this?

Why? Dear god, why? I can already imagine the question coming up why anyone would ever do this. I wasn't a big fan of Golang templates when i first had to write some custom formatting strings for docker. Learning a new template language usually isn't something one is looking forward to. Most people avoid it completely. However, it's really useful for automation if you're looking for something more lightweight than a full blown DSL.

The main motivation for this is to make it easier to write devops tools in Rust that feel native. [docker] and [helm] ([kubernetes]) use golang templates and it feels more native if tooling around them uses the same.

[gtmpl-rust]: https://github.com/fiji-flo/gtmpl-rust [Golang text/template]: https://golang.org/pkg/text/template/ [kubernetes]: https://kubernetes.io [helm]: https://github.com/kubernetes/helm/blob/master/docs/chartbestpractices/templates.md [docker]: https://docker.com [gtmplvalue]: https://github.com/fiji-flo/gtmplvalue [gtmplderive]: https://github.com/fiji-flo/gtmplderive

πŸ”— More in this category

Β© 2026 GitRepoTrend Β· fiji-flo/gtmpl-rust Β· Updated daily from GitHub