Clients
TypeScript client
Install the TypeScript client, render a PDF from Node.js in a child process or through brevier serve, and handle errors. Needs Node.js 22 or newer.
On this page
The TypeScript client calls the Brevier engine from Node.js. You pass HTML and data, and you get the PDF back. It needs Node.js 22 or newer. The engine does the layout, so you write no PDF drawing code.
There are two modes:
| Mode | How the client reaches the engine | Use it for |
|---|---|---|
| Child process | It starts the brevier command for each render. |
Development, scripts and batch jobs |
| Serve mode | It calls a running brevier serve over HTTP. |
Production and many renders |
Install the engine
The engine is the brevier command. Child process mode starts it, so it must
be on the PATH of the machine that runs your Node.js code:
pip install brevierOther ways to install it are on the Installation page.
Get a trial key
Every render needs a licence key, also for testing. Get the key before the first render.
- Request a free 30-day trial key on the pricing page. It arrives by email.
- Set the
BREVIER_LICENCE_KEYenvironment variable:
export BREVIER_LICENCE_KEY="<your-licence-key>"$env:BREVIER_LICENCE_KEY = "<your-licence-key>"The engine reads the key from its environment. The client passes your
environment on to the child process. In serve mode, set the key in the shell
that starts brevier serve.
Add the client
npm install brevierChild process
This program renders a PDF from an HTML string and an object:
import { Pdf } from 'brevier';
async function main(): Promise<void> {
await Pdf.builder()
.withHtml('<h1>Hello {{ name }}</h1>')
.withData({ name: 'World' })
.toFile('hello.pdf');
}
main();Compile it with tsc and run it with node. The folder now has hello.pdf.
withHtmlandwithCsstake the layout as text.withHtmlFileandwithCssFileread it from a file.withDatatakes any object.withJsontakes JSON text.toBytesreturns the PDF.toFilewrites it to a path.
Serve mode
In serve mode the engine runs as a service, and your code asks it for a PDF by the name of a template. A template is a folder with a file of the same name:
<!DOCTYPE html>
<html lang="en">
<body>
<h1>Hello {{ name }}</h1>
</body>
</html>Start the server in the folder that holds templates:
brevier serve --templates templatesThe server listens on 127.0.0.1:8080. It has no TLS and no login, so put a
gateway in front of it before you expose it. Then render the template from
Node.js:
import { writeFile } from 'node:fs/promises';
import { template } from 'brevier';
async function main(): Promise<void> {
const pdf = await template('hello', { url: 'http://127.0.0.1:8080' })
.with('name', 'World')
.render();
await writeFile('hello.pdf', pdf);
}
main();with(name, value)sets one root of the template.with(map)sets several.rows(list)sets the rows of a table.render({ konto, buchungen })binds each key to a root of the template.- Without
url, the client reads the environment variableBREVIER_URL. Without that, it startsbrevier serve --stdioas a child process. It reads thetemplatesfolder of the working directory and reuses the process.
How do I render many PDFs at once?
Pdf.batch() renders every HTML file of a folder, and its subfolders, into
one PDF each. All files get the same CSS. The batch passes no data: each file
must already be the finished page, for example from your own template engine.
import { Pdf } from 'brevier';
async function main(): Promise<void> {
const batch = await Pdf.batch().withInput('letters', '*.html').withCssFile('company.css');
const written = await batch.withOutput('out').toFiles();
written.forEach((file) => console.log(file));
}
main();With letters/2026-001.html and letters/2026-002.html, the program prints
one line per PDF it wrote, in the order it found the files:
out/2026-001.pdf
out/2026-002.pdfFor one PDF per record of your data, call Pdf.builder() in a loop instead. A
subfolder of letters comes back as the same subfolder of out. When one
file fails, toFiles stops and rejects with a BrevierException.
How do I send the PDF from a web endpoint?
Render to a Buffer and send it with the content type application/pdf. In
Express:
import express from 'express';
import { template } from 'brevier';
const app = express();
app.get('/invoices/:id/pdf', async (req, res) => {
const rechnung = await invoices.find(req.params.id);
const pdf = await template('rechnung').render({ rechnung });
res.type('application/pdf').send(pdf);
});invoices is your own data access. Set BREVIER_URL on the server, and every
render goes to your running brevier serve. The code does not change.
How do I get HTML instead of a PDF?
Html.builder() takes the same calls as Pdf.builder() and returns HTML. Use
it to show the document in a web portal, or to compare it in a test:
const html = await Html.builder()
.withHtml('<h1>Hello {{ name }}</h1>')
.withData({ name: 'World' })
.toBytes();The class names of this HTML stay stable between releases. Output and tests shows how to use it in a snapshot test.
Replace a JasperReports or Word call
If your service fills a JasperReports report or a Word file today, import the template first. Then replace the call in two steps.
Step 1 keeps your data object and passes the rows:
return await Brevier.template("kontoauszug").with(data).rows(buchungen).render();Step 2 passes your objects. The keys of the object are the roots of the template.
return await Brevier.template("kontoauszug").render({ konto, kunde, buchungen });Errors
The client throws a BrevierException. It has code, the error code of the
engine such as DATA_ERROR, and path, the place in the data where the
problem is. The message never holds a value from your data.