poi-tl: a logic-less Word template engine for Java
Generate awesome word(docx) with template
At a glance
- What is it?
- poi-tl generates new .docx files from a Word template and a data model, keeping the template's styles. Here is how the tag system works, how to install it, and where it stops being the right tool.
- Who is it for?
- poi-tl fits teams that already design documents in Word and want the file itself to stay the source of layout: reports, contracts, certificates and exports where a designer owns the .docx and a Java service owns the data. It is the wrong choice when the document needs branching logic that only the template author can express, or when the output is not a Word file at all.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 53 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap poi-tl fills between Word and Java
Java has no shortage of ways to produce a .docx. Apache POI gives you the object model but makes you assemble paragraphs, runs and tables in code, which pushes layout decisions into Java. Text template engines such as FreeMarker or Velocity work on plain text, so a .docx, which is a zip of XML parts, is not something they can fill in without corrupting the file. poi-tl takes the third position: the template stays a real Word document, and the engine replaces marked regions inside it.
The audience is narrow and identifiable. It is a backend team that receives a .docx from someone who cares about typography, and needs to emit the same document once per record with values swapped in. The README frames the model as Template + data-model = output, and states that the styles in the template are retained in the generated document, with the style of a tag applied to the replaced text. That single property is the reason to pick it over building documents from scratch in POI: the person editing the template controls the appearance, and the Java code only supplies values.
Tags, not control flow: how the rendering model works
A tag is two curly braces around a name, and the optional character before the name selects the tag type. The README gives the examples `{{title}}` for text, `{{?title}}` for a condition, `{{@logo}}` for a picture and `{{#table}}` for a table. The engine reads the document, finds these regions, and substitutes content according to the type.
The project describes itself as logic-less and quotes the Google CTemplate guide on the cost of putting variable assignment and conditionals inside templates: the template turns into part of the application logic. poi-tl follows that reasoning. There is no assignment statement and no general expression syntax in the tag grammar. What exists instead is a fixed set of tag types: text, picture, table, numbering, a conditional that hides or shows document content, and a foreach that repeats a block. The README lists looping a table row, looping a table column and looping ordered lists as separate capabilities, which matters because each of those needs different handling of the underlying XML.
Data flows one way. You compile a template file, hand it a map or model object, and write the result. The README's quick start reduces the core call to a single chained line, and notes that when a key is absent from the model, the tag is cleared by default, with a configurable choice to keep the tag or throw instead. That default is worth knowing before a first run: a missing key produces a document with a hole in it, not an error.
Beyond the built-in tags, the engine exposes custom functions, described as plug-ins that can run anywhere in the document. The repository layout reflects that: `poi-tl-plugin-highlight` and `poi-tl-plugin-markdown` sit as separate modules, alongside `poi-tl-cli` and `poi-tl-jsonmodel-support`. Markdown to Word and code highlighting with 26 languages are shipped as plug-ins rather than baked into the core, which keeps the core artifact smaller and lets you leave out what you do not use.
Installing poi-tl with Maven and rendering a first document
poi-tl is published to Maven Central under the group `com.deepoove`, so installation is a dependency entry, not a download. The README shows version 1.12.2, which is also the most recent release listed for the project.
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.2</version>
</dependency>There is a version constraint attached to that entry. The README states that poi-tl 1.12.x requires POI version 5.2.2 or later, while the badges at the top of the file advertise support from POI 3.16 upward and JDK 1.6+. If your project already pins an older POI, resolve that conflict before writing any template code, because poi-tl operates on POI's object model directly.
For a first run, create a Word file named `template.docx` containing the literal text `{{title}}`, then render it:
XWPFTemplate.compile("template.docx").render(new HashMap<String, Object>(){{
put("title", "poi-tl template engine");
}}).writeToFile("out_template.docx");Opening `out_template.docx` should show the sentence with the tag replaced. The README calls this the TDO mode, template plus data model equals output, and notes the core API needs only that one line. From there, the same call accepts picture values, table data, and collections for the foreach tags without changing the shape of the code.
Where poi-tl is the wrong tool
The logic-less design has a cost, and it shows up as soon as the document needs a decision the tag grammar cannot express. A conditional tag handles show or hide. A foreach handles repetition. Anything more elaborate, such as a computed subtotal that depends on the rows above it, or a layout that changes shape based on a combination of fields, has to be prepared in Java before rendering. The template author cannot solve it alone, and the separation the project is built around starts to leak.
There is a second boundary. The README describes poi-tl as a Word template engine that generates new documents. If the deliverable is a PDF, an HTML page or a spreadsheet, the engine is aimed at the wrong format, even though it can insert a Word attachment or convert Markdown into a document as side features. The output is a .docx, and the value proposition assumes downstream consumers accept one.
Version cadence is a practical consideration rather than a defect. The releases listed for the project are v1.12.2 from 2024-01-25, v1.12.1 from 2022-12-29 and v1.12.0 from 2022-04-14, while the last push to the repository was on 2026-08-08. The repository is not archived, and commits continue, but a dependency pinned to 1.12.2 is pinned to a release that has not been superseded in the release list. Teams that require frequent tagged releases to justify an upgrade should note that gap.
How poi-tl differs from filling documents with Apache POI alone
The obvious alternative is to skip the template engine and write the document with Apache POI directly. The difference is where the layout lives. With POI alone, every paragraph, run, style and table cell is constructed in Java, so a change to the visual design is a code change and a redeploy, and the person who understands the document has to describe it to the person who writes the Java. With poi-tl, that person edits the .docx and the code keeps supplying the same keys.
That trade is not free in either direction. Direct POI use gives you full control over every part of the file and has no tag grammar to learn or to escape, which matters for documents whose structure is generated rather than designed. poi-tl gives up that control in exchange for keeping the template authoritative, and the cost is the constraint described above: whatever the tag types cannot express has to be computed before rendering. Picking between them is really a question of who owns the document's appearance. If a designer does, the template engine earns its place. If the structure is derived entirely from data, the engine is an extra layer.
Licence, maintenance and what an upgrade costs
poi-tl is licensed under Apache-2.0, which is a permissive licence that permits commercial use and modification and requires the licence and notices to be preserved. That is a statement about the licence text, not legal advice; if your organisation has a policy on dependency licences, the identifier to check against it is Apache-2.0. The repository also carries a `poi-ooxml-schemas-extra` directory, which is worth a look if you hit schema classes the standard POI artifacts do not include.
The upgrade surface is smaller than it looks because the public API in the README is one chained call. The real cost sits in the version constraint: 1.12.x needs POI 5.2.2 or later, so a poi-tl upgrade can drag a POI upgrade behind it, and POI upgrades are the ones that tend to break code touching the XML object model. Custom plug-ins are the other place to look, since they are written against poi-tl's internals rather than the tag grammar, and the two shipped plug-ins in this repository are the best reference for what that interface expects.
Editorial conclusion
poi-tl fits teams that already design documents in Word and want the file itself to stay the source of layout: reports, contracts, certificates and exports where a designer owns the .docx and a Java service owns the data. It is the wrong choice when the document needs branching logic that only the template author can express, or when the output is not a Word file at all. Before adopting it, confirm the POI version your project already pulls in, because poi-tl 1.12.x requires POI 5.2.2+, and check that the tag syntax your templates use is covered by the tag types the README lists.
Frequently asked questions
What does Apache POI do?
Apache POI is the underlying library poi-tl is based on, and poi-tl operates on its object model directly. The README states that poi-tl 1.12.x requires POI version 5.2.2 or later.
What is the latest version of Apache POI?
The README does not state the latest POI release. It only gives the version constraint that poi-tl 1.12.x requires POI 5.2.2 or later, while the badges advertise support from POI 3.16 upward.
What is poi-tl in relation to Apache POI?
poi-tl is a Word template engine that generates new .docx documents from a Word template and a data model, and the README describes it as based on Apache POI. The badges list support from POI 3.16 upward and JDK 1.6+, while the 1.12.x line requires POI 5.2.2 or later.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/sayi-poi-tl)