---
title: "Word documents from data in JavaScript — quario"
description: "Generate .docx files from your data in JavaScript. One definition, real Word tables, a navigation outline, and page numbers Word keeps live — no Word install, no headless browser."
url: "https://getquario.com/guides/docx-template"
---

# Word documents, in JavaScript

You need a `.docx` — something a colleague opens, reads, and edits. The thing to
settle before you start is who decides where the pages break, because for Word
it isn’t you. quario states the geometry and the typography; Word does the
paginating when the file opens.

## The approach in one line

**Your data + a report definition → a `.docx`.** No Word install on the server,
no headless browser, no template file to fill in. The same definition that
renders a PDF renders the Word file.

## Do it with quario

Install:

```bash title="shell"
npm install @quario/docx
```

Describe the report once. Two declarations here do work that only Word cashes
in: `groups` becomes the navigation pane, and the bare `{{ page.number }}` in
`page.footer` becomes a field Word recomputes for itself.

```json title="review.report.json"
{
  "data": "$.entries[*]",
  "aggregates": { "total": "sum:=@.amount" },
  "header": [
    { "type": "text",
      "value": "Quarterly review",
      "style": { "size": 20, "bold": true, "spaceAfter": 10 } }
  ],
  "groups": [
    { "name": "team",
      "by": "=@.team",
      "aggregates": { "subtotal": "sum:=@.amount" },
      "header": [
        { "type": "text",
          "value": "{{ team.key }}",
          "style": { "size": 13, "bold": true, "spaceBefore": 14, "spaceAfter": 4 } }
      ] }
  ],
  "detail": {
    "columns": [
      { "header": "Item", "value": "{{ @.item }}", "width": 70 },
      { "header": { "value": "Amount", "style": { "align": "right" } },
        "value": "{{ @.amount }}",
        "style": { "align": "right", "format": "currency" }, "width": 30 }
    ],
    "total": {
      "style": { "align": "right", "bold": true },
      "rows": [
        { "cells": [
          { "value": "Subtotal {{ team.key }}" },
          { "value": "{{ round(team.subtotal, 2) }}", "style": { "format": "currency" } }
        ] }
      ]
    }
  },
  "page": {
    "footer": [
      { "type": "text", "value": "Page {{ page.number }} of {{ page.total }}", "style": { "size": 8 } }
    ]
  }
}
```

Render it:

```ts title="app.ts"
import { writeFileSync } from 'node:fs'
import { quario } from 'quario'
import { docx } from '@quario/docx'
import definition from './review.report.json' with { type: 'json' }

const report = quario({ locale: 'en-IE', currency: 'EUR' }).report(definition)

const bytes = await report.render(
  docx({ page: { size: 'A4' }, meta: { title: 'Quarterly review' } }),
  data,
)

writeFileSync('review.docx', bytes)
```

## Word paginates, not quario

`@quario/docx` is a **flow** target. It runs no layout of its own: it states the
geometry and the typography, and the reader’s application decides where page two
starts. The promise is the same look, not the same page breaks.

That’s the trade against [the PDF target](https://getquario.com/guides/json-to-pdf.md), which paints its
own pages and can therefore promise where every line falls. Pick by which promise
you need. A document someone will edit wants Word. A document that must look
identical on every desk wants the PDF.

## What Word gives you back

**A navigation outline.** Each group header’s first item takes a heading style by
depth, so the grouping you already declared becomes the navigation pane. Nothing
extra to declare.

**Live page numbers.** A bare `{{ page.number }}` or `{{ page.total }}` becomes a
`PAGE` or `NUMPAGES` field. Delete a paragraph in Word and the numbering
corrects itself, because Word owns it now. Anything you *compute* from those
tokens freezes at render instead, which is the one place the flow model shows
through.

**Real tables.** A `detail` is a Word table, not a picture of one. Declared
column widths are exact, the header row repeats across page breaks, and a reader
can put their cursor in a cell and type.

## You may not need to write a definition

Every [template](https://getquario.com/templates.md) on this site is a definition, and a definition is
target-blind. The invoice, the statement, the payslip, and the rest all render to
Word through the same call as above — nothing about them is PDF-specific. If you
came looking for a Word template, start there and change the parts that are
yours.

## FAQ

### Does the server need Word installed?

No. `@quario/docx` writes the OOXML package itself, and its only runtime
dependency is a zip writer. There’s no Word, no LibreOffice, and no headless
browser anywhere in the path.

### Can I control where the pages break?

Only coarsely, and on purpose. A group’s `break` places the page turns around its
instances — `"before"`, `"between"`, `"after"` or `"around"` — and `reset: "page"`
restarts the numbering, which needs a `break` of `"before"` or `"around"` beside
it. Beyond that the breaks are Word’s. If you need them to be yours, render
[the same definition to PDF](https://getquario.com/guides/json-to-pdf.md).

### Are the bytes deterministic?

Yes. The same schema, data and options produce byte-identical output on every
supported runtime. Every zip entry carries the same fixed stamp, and no part of
the package holds a clock.

### How big is it?

The engine is under 5 kB minified and compressed, and the DOCX target adds its
own on top, plus a zip writer.

### Can I use it for free?

Evaluating it’s free and has no time limit — the full engine, no key to request —
and evaluation output carries a watermark. Anything past evaluating it, including
shipping it in an application or running it in your business, needs a license for
each production deployment. Its users, agents, and renders are never counted, and
replicas of one service count once. [See pricing →](https://getquario.com/pricing.md)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://getquario.com/"},{"@type":"ListItem","position":2,"name":"Guides","item":"https://getquario.com/guides"},{"@type":"ListItem","position":3,"name":"Word documents","item":"https://getquario.com/guides/docx-template"}]}
```
