NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
crates.io · #1637 most downloaded on crates.io
a powerful template engine for Rust with minimal dependencies
Last release 2 days ago
15 Sep 2026
Ships fairly regularly
a new release about every 3 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
5 years old
115 releases · first in 2021
One column per quarter.
Fixed a bug that caused {% raw %} blocks to accidentally not skip the surrounding tags, causing {% raw %} and {% endraw %} to show up in output.
{% raw %} blocks to accidentally not skip the
surrounding tags, causing {% raw %} and {% endraw %} to show up in
output. (#307)Support unicode sorting for filters when the unicode feature is enabled. This also fixes confusing behavior when mixed types were sorted.
Support unicode sorting for filters when the unicode feature is enabled.
This also fixes confusing behavior when mixed types were sorted. (#299)
Added json5 as file extension for JSON formatter.
The autoreload crate now supports fast reloading by just clearing the
already templates. This is enabled via set_fast_reload on the
Notifier.
Note: This also includes all the changes in the different 1.0.0 alphas.
1.0 includes a lot of changes that are breaking. However they should with some minor exceptions be rather trivial changes.
Environment::source, Environment::set_source and the Source type
together with the source feature were removed. The replacement is the
new loader feature which adds the add_template_owned and set_loader
APIs. The functionality previously provided by Source::from_path is
now available via path_loader.
Old:
let mut source = Source::with_loader(|name| ...);
source.add_template("foo", "...").unwrap();
let mut env = Environment::new();
env.set_source(source);
New:
let mut env = Environment::new();
env.set_loader(|name| ...);
env.add_template_owned("foo", "...").unwrap();
Old:
let mut env = Environment::new();
env.set_source(Source::from_path("templates"));
New:
let mut env = Environment::new();
env.set_loader(path_loader("templates"));
Template::render_block and Template::render_block_to_write were
replaced with APIs of the same name on the State returned by
Template::eval_to_state or Template::render_and_return_state:
Old:
let rv = tmpl.render_block("name", ctx)?;
New:
let rv = tmpl.eval_to_state(ctx)?.render_block("name")?;
Kwargs::from_args was removed as API as it's no longer necessary since
the from_args function now provides the same functionality:
Before:
// just split
let (args, kwargs) = Kwargs::from_args(values);
// split and parse
let (args, kwargs) = Kwargs::from_args(values);
let (a, b): (i32, i32) = from_args(args)?;
After:
// just split
let (args, kwargs): (&[Value], Kwargs) = from_args(values)?;
// split and parse
let (a, b, kwargs): (i32, i32, Kwargs) = from_args(values)?;
The testutils feature and testutils module were removed. Instead you
can now directly create an empty State and use the methods provided
to invoke filters.
Before:
let env = Environment::new();
let rv = apply_filter(&env, "upper", &["hello world".into()]).unwrap();
After:
let env = Environment::new();
let rv = env.empty_state().apply_filter("upper", &["hello world".into()]).unwrap();
Before:
let env = Environment::new();
let rv = perform_test(&env, "even", &[42.into()]).unwrap();
After:
let env = Environment::new();
let rv = env.empty_state().perform_test("even", &[42.into()]).unwrap();
Before:
let env = Environment::new();
let rv = format(&env, 42.into()).unwrap();
After:
let env = Environment::new();
let rv = env.empty_state().format(42.into()).unwrap();
intern and some APIs that use Arc<String> now use Arc<str>. This
means that for instance StructObject::fields returns Arc<str> instead
of Arc<String>. All the type conversions that previously accepted
Arc<String> now only support Arc<str>.
State::current_call was removed without replacement. This information
was unreliably maintained in the engine and caused issues with recursive
calls. If you have a need for this API please reach out on the issue
tracker.
Output::is_discarding was removed without replacement. This is
an implementation detail and was unintentionally exposed. You should not
write code that depends on the internal state of the Output.
Value now implements Ord. This also improves the ability of the engine to sort more complex values in filters.
Value now implements Ord. This also improves the ability of the engine
to sort more complex values in filters. (#295)
Arc<String> was replaced with Arc<str> in some of the public APIs where
this shined through. Support for more complex key types in maps was added.
You can now have tuple keys for instance. (#297)
Removed char as a value type. Characters are now represented as strings instead. This solves a bunch of Jinja2 incompatibilities that resulted by inde
Removed char as a value type. Characters are now represented as strings
instead. This solves a bunch of Jinja2 incompatibilities that resulted by
indexing into strings. (#292)
Marked ErrorKind as #[non_exhaustive].
Correctly handle coercing of characters and strings. "w" == "w"[0] is
now evaluating to true as one would expect.
The include block now supports with context and without context modifiers but they are ignored. This is mostly helpful to render some Jinja2 templates
The include block now supports with context and without context
modifiers but they are ignored. This is mostly helpful to render some
Jinja2 templates that depend on this functionality. (#288)
Added tests true, false, filter, test and filters
pprint and unique. (#287)
Added support for indexing into strings. (#149)
Added Error::detail which returns the detail help string. (#289)
Added Error::template_source and Error::range to better support
rendering of errors outside of the built-in debug printing. (#286)
Removed testutils feature. New replacement APIs are directly available on the State.
Removed testutils feature. New replacement APIs are directly available
on the State.
Added Template::render_and_return_state to render a template and return the
resulting State to permit introspection. Template::render_to_write now
also returns the State.
Added State::fuel_levels to introspect fuel consumption when the fuel feature
is in use.
Removed Source and the source feature. The replacement is the new loader
feature and the functionality of the source is moved directly into the
Environment. This also adds Environment::clear_templates to unload
all already loaded templates. (#275)
Added Environment::template_from_str and Environment::template_from_named_str
to compile templates for temporary use. (#274)
Removed Kwargs::from_args as this can now be expressed with just
from_args. (#273)
Output no longer reveals if it's discarding in the public API.
Added Value::call, Value::call_method and Template::new_state. The
combination of these APIs makes it possible to call values which was
previously not possible. (#272)
Added Template::eval_to_state. This replaces the functionality of the
previous Template::render_block which is now available via State.
It also adds support for accessing globals and macros from a template
via the State. (#271)
Removed support for State::current_call. This property wasn't too useful
and unreliable. Supporting it properly for nested invocations would require
calls to take a mutable state or use interior mutability which did not seem
reasonable for this. (#269)
Updated self_cell and percent-encoding dependencies.
Updated self_cell and percent-encoding dependencies. (#264)
Added Template::render_block and Template::render_block_to_write which
allows rendering a single block in isolation. (#262)
Hide accidentally exposed Syntax::compile method.
Syntax::compile method.undeclared_variables methods to Template and Expression. (#250)Fixed an issue with autoreload not working properly on windows.
TryFrom for Value now converts integers to f32 and f64.
Value::is_number. (#240)TryFrom for Value now converts integers to f32 and f64.custom_syntax feature which allows custom delimiters
to be configured. (#245)Kwargs abstraction to easier handle keyword arguments.Option<T> was incorrectly picking up none
for undefined values.sort filter now accepts reverse, attribute and case_sensitive
by keyword argument and sorts case insensitive by default.dictsort filter now supports reversing, by value sorting,
and is sorting case insensitive by default.The in operator now does not fail if the value is undefined and the undefined behavior is not strict.
in operator now does not fail if the value is undefined and the
undefined behavior is not strict. (#235)Changed the closure behavior of macros to match the one of Jinja2.
Value::from_serializable will no longer panic on invalid values. Instead
the error is deferred to runtime which makes working with objects possible
that are only partially valid for the runtime environment. (#234)Make it more obvious that serde flatten sometimes does not work.
testutils module. (#221)render!() reuse the hidden environment.Resolve bad closure being generated for do blocks.
do blocks. (#219)Small performance improvements for when preserve_order is used by passing known capacities to the constructor.
preserve_order is used by
passing known capacities to the constructor.u32 rather than
usize for line and column offsets as a small speed improvement during
compilation.key_interning by default.multi-template to multi_template and
adjacent-loop-items to adjacent_loop_items. The old feature names will
hang around until 1.x as legacy aliases.Restore compilation on 32bit targets.
Added the Jinja2 tests ==, !=, <, <=, >, >= and in for the use with select and reject.
==, !=, <, <=, >, >= and in for the
use with select and reject. (#205)Fixed Python bindings not allowing to access dict keys prefixed with an underscore.
min, max and sort filters. (#199)Changed add_global to perform Into implicitly.
add_global to perform Into<Value> implicitly.source_mut to retrieve a mutable reference to the source.pass_state to the Python binding.Expose debug flag from environment.
debug flag from environment.Resolve a runtime panic if {% extends %} appears in the template but never is executed.
{% extends %} appears in the template
but never is executed.none test. (#185)Value::default now returns Undefined rather than None.loop.previtem and loop.nextitem. (#188)Improved testsuite to execute on wasm32-wasi.
capitalize filter. (#163){% call %}. (#164){% do %}. (#167)Filters, tests and other functions can now be registered with a dynamically allocated name.
State::current_call which exposes the name of the currently called
item. (#150)SeqObject and StructObject. (#148)Object now directly exposes downcast_ref and is.Value::as_sliceValue::as_seq and Value::as_struct.Value::from_seq_object and Value::from_struct_object.&dyn SeqObject.Iter to ValueIter.Environment::render_named_str. (#149)intern function.indent filter. (#151)map, select / selectattr and reject / rejectattr filters.safe / escaped test.Object model changed significantly in this release. It's now possible
for objects to have different shapes (structs or sequences today). As a result
SeqObject and StructObject were added to the API. For changing your objects
over have a look at the new documentation for Object.Iter type is now called ValueIter.Changed Object::attributes to being an iterator.
Object::attributes to being an iterator. (#138)Arc<T: Object> now implements Object. (#139)extends with Jinja2. (#140)attributes method on objects now returns iterators. To make the
transition easy change [..] to Box::new([..].into_iter()).Added support for recursive macro invocations.
Enforce a maximum recursion depth during parsing.
inf floats.Value::try_iter to iterate over maps and sequences. (#132)Fixed incorrect location information with blocks.
Value::from_function. (#121)super() calls.super() when there is no parent block.{% import %} / {% from .. import .. %}
and {% macro %}. (#123)Value::is_kwargs which disambiguates if an object passed
to a function or filter is a normal object or if it represents
keyword arguments.macros and multi_template features to disable some of
the heavier pieces of MiniJinja.Fixed an incorrect manifest for minijinja-autoreload.
minijinja-autoreload.Add defined and undefined tests to always be included.
defined and undefined tests to always be included.Source::load_from_path.Source::from_path.Source::load_from_path. Use Source::with_loader instead.Added custom autoescape settings.
io::Write. (#111)Filter, Test or Function
from outside the crate by sealed the traits. (#113)Rest. (#114)Value::as_slice and Value::get_get_item_by_index.ImpossibleOperation is now InvalidOperation.Filter, Test and Function are now sealed traits.ErrorKind::ImpossibleOperation is now ErrorKind::InvalidOperation.Remove internal refcounts from environment.
Object and FunctionArgs interface to take
arguments by reference. (#101)sync mode is now always enabled. (#104)PartialEq.meta API is gone without replacement.Object::call_method and Object::call now take the arguments
as &[Value] instead of Vec<Value>.Object::call_method, Object::call and FunctionArgs::from_values
now take the arguments as &[Value] instead of Vec<Value>.PartialEq but this was implemented
by comparing the error kind instead. Explicitly use the .kind()
method of the error if you want the same behavior.DebugInfo is no longer exposed. This might come back if a better
API can be found.Fixed binary subtraction operator requiring a space.
Small internal improvements to context creation.
'). (#81)+ for Jinja compat. (#87)render! macro and render_str. (#89)loop.changed() method. (#91)Fixed a bad dependency declaration.
Improved debug printing of context.
-, _ and . to set of unescaped characters in urlencode. (#72)v_htmlescape dependency. (#74)Minimum Rust version moved up to 1.45.
{% raw %}. (#67){% set %}. (#70)Added support for unpacking in with blocks.
with blocks. (#65)Bumped minimum version requirement to 1.43.
Source::with_loader.get_source to source.Fixed or expressions not working properly.
or expressions not working properly.Added support for ignore missing in include tags.
bool filter.meta API. (#55)ignore missing in include tags. (#56)Removed deprecated functionality.
Deprecated Primitive and as_primitive.
Primitive and as_primitive.as_f64.batch and slice filter.items filter.list filter.first and last filters.round and abs filters.//) and changed division to always
return floats like documented and to match the Jinja2 implementation. To
make this more convenient whole integer floats are now handled like integers in
some situations.recursive support to for loops.builtin_filters, builtin_tests and builtin_functions features
into builtins.value::serializing_for_value to check if serialization is taking place
for MiniJinja.Value type now supports deserialization. This feature can be disabled
by removing the default deserialization feature.memchr dependency as it does not appear to be useful.*Yanked* — this was a release from the wrong branch
Yanked — this was a release from the wrong branch
Removed deprecated Single type.
debug support. If the debug mode is enabled, errors now carry a lot of
useful debug information and an alternative representation when formatted into
strings that show the context of the template where it went all wrong. (#31)key_interning feature. (#35)Single type.Remove one trailing newline to be consistent with Jinja2.
Restored unconditional compatibility with 1.42.
Turned on all features for the docs on docs.rs
Added context! and deprecate Single.
context! and deprecate Single.source method on templates.State type and changed parameter to functions from
&Environment to &State.debug global.tojson filter.urlencode filter.Made the source method on error be bound to Send and Sync.
source method on error be bound to Send and Sync.Added startingwith and endingwith tests.
default filter.startingwith and endingwith tests.range function.dict function.super() calls outside of blocks.Error::with_source method.object abstraction.e, d and count.Added v_htmlescape feature to turn on a faster HTML escaping.
v_htmlescape feature to turn on a faster HTML escaping.HtmlEscape helper./ in HTML escaping like v_htmlescape does.get_template to be a result rather than an
option.Source behind the source feature to support loading of templates
at runtime without lifetime complications.sync feature that can be disabled to disable the ability to send
objects to other threads where that comes at a cost.safe and escape are now always provided as filters.self.block_name().super() did not allow filters.{% filter %} blocks.value::Single type to render simple templates with a single value passed.Added the ability to roundtrip arbitrary values via the serialize interface.
ArgType to handle argument conversions for filters
and tests so optional arguments can exist.ValueArgs trait to FunctionArgs.reverse filter.trim filter.join filter.number test.string test.sequence test.mapping test.builtin_filters and builtin_tests features to disable the built-in
filter and test functions.is not syntax for negated tests.else block to for loops.if condition expression to for loops.in and not in expressions.if expressions.Added support for {% include %}
{% include %}with blocks to fully shadow the outer scope.Added support for rustc versions down to 1.42.0
- Initial release of the library
Your coding agent can read these notes before it upgrades. Set up the MCP server →