Skip to content

Quickstart

1. Write the template in Word

Create the document as you want it to look. Where a value goes, type a tag:

Dear {{ customer.name }},

Your order of {{ order.date }} totalling {{ total }} has shipped.

Formatting applies to tags as it does to any other text — make the tag bold and the rendered value is bold.

2. Render it

from docxtpl import Template

tpl = Template("letter.docx")
tpl.render({
    "customer": {"name": "Acme GmbH"},
    "order": {"date": "2026-08-04"},
    "total": "€1,240.00",
})
tpl.save("letter-acme.docx")

3. Repeat a table row

Prefix the loop tags with tr so that the row is what repeats rather than the text. A prefixed tag removes the element it names, so the two tags go in rows of their own, above and below the row that repeats — a {%tr for %} in the repeating row would take that row's content with it.

Item Qty Price
{%tr for line in lines %}
{{ line.name }} {{ line.qty }} {{ line.price }}
{%tr endfor %}

The two tag rows never appear in the rendered document. See Template syntax for the rest of the dialect, and Tables for merging and shading cells.

4. Render the same template many times

Rendering mutates the document, so a second render() applies to the first render's output. To run one template over many contexts, reload between them:

tpl = Template("letter.docx")
for customer in customers:
    tpl.reload()
    tpl.render({"customer": customer})
    tpl.save(f"letter-{customer.id}.docx")

is_rendered says whether a render has happened, if you would rather check than reload. In the compatibility API the same method is init_docx().

5. From the command line

For build pipelines, and the fastest way to reproduce a problem:

docxtpl-ng letter.docx context.json letter-acme.docx