# jmustache: Mustache templates in Java with two methods and no dependencies

> JMustache is a Java implementation of the Mustache templating language whose pitch is restraint: no dependencies, two API methods, and very limited demands on the JVM so it runs on Android. The judgement is that the design choices are coherent, and that the value for most teams is in the context resolution rules rather than the template syntax itself.

**samskivert/jmustache** — A Java implementation of the Mustache templating language.

- Repository: https://github.com/samskivert/jmustache
- Stars: 883 · Forks: 134
- Language: Java
- License: NOASSERTION
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/samskivert-jmustache

## Four reasons the library exists

The README opens with the motivations, and read in order they explain most of the design. Zero dependencies comes first: you can include this single tiny library in your project and start making use of templates. Usability on a variety of target platforms comes second, and the claim is specific, that this implementation makes very limited demands on the JVM in which it runs, and as a result is usable on Android, or on other limited JVMs, with the further note that it is even possible to avoid the use of reflection and provide all of your data as a series of nested maps. Proguard and JarJar friendliness is the third, and the reasoning is that although the library will reflectively access your data if you desire it, it makes no other internal use of reflection or by name instantiation of classes, so you can embed it using Proguard or JarJar without any annoying surprises. The fourth motivation is a minimal API footprint, since there are really only two methods you need to know about, compile and execute, and you can even chain them together in cases where performance is of no consequence.

## One dependency line, or one jar file

Distribution is deliberately boring. JMustache is available via Maven Central, so it can be added to a Maven, Ivy or similar project by depending on com.samskivert:jmustache:1.15, and the README also points at the pre-built jar file on the Maven Central repository for people who are not using a dependency manager at all. For an Android project, the jar plus the Proguard note above is a complete installation story. Two documentation links sit alongside the usage section: the API docs are published on a site under the author's name, and the Mustache manual itself is linked for anyone who needs the template syntax rather than the Java API. The repository reflects a Maven project rather than a hand rolled one, with a pom.xml at the root, the Maven wrapper scripts mvnw and mvnw.cmd, an .mvn directory and a .travis.yml file for continuous integration, and the sources under src. The licence is recorded as a custom one that GitHub cannot classify, so the LICENSE file is the text to read before you ship it, and the project publishes no GitHub releases, with the last push on 2026-10-03.

## Context resolution follows a fixed ladder

The execution context can be any Java object, and the README lists the resolution mechanisms in order. If the context is a MustacheCustomContext, its get method will be used. If the context is a Map, Map.get will be used. If a non-void method with the same name as the variable exists, it will be called. If a non-void method named getFoo exists for a variable foo, it will be called. If a field with the same name as the variable exists, its contents will be used. The README shows a small Person class with a public final name field, a protected _age field and a getAge accessor, rendered by a template that iterates a section over a list:

```java
String tmpl = "{{#persons}}{{name}}: {{age}}\n{{/persons}}";
Mustache.compiler().compile(tmpl).execute(new Object() {
    Object persons = Arrays.asList(new Person("Elvis", 75), new Person("Madonna", 52));
});
```

Two details in that snippet decide whether your data model works with the library. The fields and methods need not be public, and the persons field in the anonymous context class is accessible, but the README warns that the use of non-public fields will not work in a sandboxed security environment. That caveat matters on Android, where reflection into non-public members of other classes is restricted.

## Sections: booleans, iterables and the null rule

Section behaviour is described in four rules, and the third one is the one that will change your output. Boolean values enable or disable the section. Array, Iterator or Iterable values repeatedly execute the section with each element used as the context for each iteration, and an empty collection results in zero instances of the section being included. An unresolvable or null value is treated as false, and that behaviour can be changed by using strictSections(). Any other object results in a single execution of the section with that object as the context. So a missing key does not blow up the render, it quietly removes the block, which is convenient until a typo in a variable name silently drops a paragraph from a customer facing page. The strictSections() switch is the mitigation, so decide deliberately which mode you want rather than discovering the difference in production.

## Partials need a TemplateLoader you supply

If you want partials, the partial syntax {{>subtmpl}}, you have to provide a Mustache.TemplateLoader to the compiler when creating it, and the README shows the shape of that interface:

```java
final File templateDir = ...;
Mustache.Compiler c = Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
    public Reader getTemplate (String name) {
        return new FileReader(new File(templateDir, name));
    }
});
String tmpl = "...{{>subtmpl}}...";
c.compile(tmpl).execute();
```

The snippet loads new File(templateDir, "subtmpl") when compiling the template, which reveals the timing: the loader is consulted at compile time, not at render time. That is the detail to keep in mind if your templates are generated or if a partial lives in a classpath resource rather than on disk, because the loader you write is the only thing standing between the template engine and your file layout. The interface has a single method, so a loader can be a classpath resource lookup, a database row or an HTTP fetch, and nothing in the library constrains that choice.

## Lambdas give you a fragment to decorate

JMustache implements lambdas by handing you a Template.Fragment instance which you can use to execute the fragment of the template that was passed to the lambda, and you can decorate the results of that fragment execution. The standard shape writes a tag around the fragment:

```java
String tmpl = "{{#bold}}{{name}} is awesome.{{/bold}}";
Mustache.compiler().compile(tmpl).execute(new Object() {
   String name = "Willy";
   Mustache.Lambda bold = new Mustache.Lambda() {
        public void execute (Template.Fragment frag, Writer out) throws IOException {
            out.write("<b>");
            frag.execute(out);
            out.write("</b>");
        }
   };
});
```

The more interesting use is the second one in the README, where the fragment result is obtained rather than written out, so the text can be looked up in an internationalisation system or cached. The template then reads like a set of keys, {{#i18n}}title{{/i18n}} and {{#i18n}}welcome_msg{{/i18n}}, and the Java side decides what those keys mean. That is the seam where a template library starts doing work a static renderer cannot, and it is the strongest argument for the library in an application with many locales.

## Parsing once, then specialising on the context class

The performance note in the README explains how the library stays reasonably fast without a lot of machinery. Templates are parsed separately from execution, and a template will specialise its variables on class of context and name pairs, so if a variable is first resolved to a field of the context object, that will be attempted directly on subsequent template invocations, and the slower full resolution will only be tried if accessing the variable as a field fails. In other words, the library learns the shape of your data after the first render and then takes a shortcut. The trade-off is inherent to the design, since the fast path depends on the context class staying the same, and a context that changes type between calls will fall back to the full ladder every time. That is not a defect, it is the price of a resolver that works on any Java object, and it is the same reason the library can run on a limited JVM in the first place.

## Conclusion

jmustache fits a Java or Android project that wants logicless templates without pulling a dependency tree into the build, especially one that has to run on a stripped down JVM, and the Proguard and JarJar friendliness is the detail that decides it for mobile work. It is the wrong choice if your team wants template logic in the template, since the whole design is built around the absence of logic, and it is a poor fit if you need the strictest possible resolution behaviour, since an unresolvable value is treated as false unless you switch on strictSections(). Before you adopt it, read the context resolution ladder in the README against the shape of your data objects, because whether a private field resolves is the question that decides whether your data model works with it.

## FAQ

### How do I render a template with JMustache?

Supply the template as a String or a Reader and get back a Template that you can execute on any context. The README shows Mustache.compiler().compile(text) followed by execute(data), and the two methods can be chained when performance does not matter.

### What kinds of context objects does JMustache support?

Any Java object. Variables are resolved in a fixed order: MustacheCustomContext.get, then Map.get, then a non-void method with the same name, then a getFoo style method, then a field with the same name. Fields and methods need not be public, though the README notes that non-public fields will not work in a sandboxed security environment.

### How do partials work in JMustache?

You provide a Mustache.TemplateLoader to the compiler when creating it, and the loader is consulted at compile time when a {{>subtmpl}} reference is met. The loader interface has a single getTemplate method, so the partials can come from a directory, a classpath resource or anything else you implement.

## Sources

- [Issues](https://github.com/samskivert/jmustache/issues)
- [README](https://github.com/samskivert/jmustache/blob/master/README.md)
- [samskivert/jmustache on GitHub](https://github.com/samskivert/jmustache)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/samskivert-jmustache
