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

Community

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 brevier

Other 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.

  1. Request a free 30-day trial key on the pricing page. It arrives by email.
  2. Set the BREVIER_LICENCE_KEY environment variable:
Linux and macOS
export BREVIER_LICENCE_KEY="<your-licence-key>"
Windows PowerShell
$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 brevier

Child process

This program renders a PDF from an HTML string and an object:

hello.ts
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.

  • withHtml and withCss take the layout as text. withHtmlFile and withCssFile read it from a file.
  • withData takes any object. withJson takes JSON text.
  • toBytes returns the PDF. toFile writes 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:

templates/hello/hello.html
<!DOCTYPE html>
<html lang="en">
<body>
  <h1>Hello {{ name }}</h1>
</body>
</html>

Start the server in the folder that holds templates:

brevier serve --templates templates

The 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:

hello-serve.ts
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 variable BREVIER_URL. Without that, it starts brevier serve --stdio as a child process. It reads the templates folder 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.

batch.ts
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:

Output
out/2026-001.pdf
out/2026-002.pdf

For 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:

server.ts
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.