Stop shipping a browser to print an invoice.
Turn the HTML templates you already have into PDFs with one function call inside Node.js. No Chromium, no Puppeteer.
Turn the HTML templates you already have into PDFs with one function call inside Node.js. No Chromium, no Puppeteer.

npm install velloraRuns on macOS (Apple Silicon and Intel) and on glibc-based Linux, x64 and arm64: Debian or Ubuntu images such as node:22-slim. No Windows or Alpine/musl builds. Node 20 or newer. MIT licensed · npm · GitHub
import { renderPdf } from "vellora";
// HTML from your own templates. Page size comes from CSS: @page { size: A4 }
export async function toPdf(html) {
return renderPdf(html); // a PDF as a Uint8Array
}import puppeteer from "puppeteer";
// One browser, launched at startup and shared by every request
const browser = await puppeteer.launch();
export async function toPdf(html) {
const page = await browser.newPage();
try {
await page.setContent(html, { waitUntil: "load" });
return await page.pdf({ format: "A4", printBackground: true });
} finally {
await page.close();
}
}FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci # vellora's renderer comes prebuilt; nothing else to install
COPY . .
CMD ["node", "server.js"]FROM node:22-slim
# The system libraries and fonts Chrome needs
RUN apt-get update && apt-get install -y \
libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
libxkbcommon0 libxcomposite1 libxdamage1 libxrandr2 libgbm1 \
libasound2 libpango-1.0-0 libcairo2 fonts-liberation \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY package*.json ./
RUN npm ci # also downloads a Chrome build
COPY . .
# ...plus --no-sandbox if the container runs as root
CMD ["node", "server.js"]Nothing to launch, keep alive or close. vellora also has built-in templating, so you can pass data as a second argument instead of building the HTML yourself. One thing to know when you switch: HTML you already rendered elsewhere should be passed with { template: false }, so a literal {{ or {% in it stays as text.
Puppeteer’s own troubleshooting guide says in its Docker section: “Getting headless Chrome up and running in Docker can be tricky.” With vellora there is no Chrome to install or start. npm install downloads the renderer prebuilt for your platform, and it runs inside your Node process. We checked that in the node:22-slim image: install, render, and a 37 MB node_modules.


On 8 of the 9 documents we test (invoices, receipts, bank slips, a letter, long Portuguese text and two popular open-source templates), every word lands within 1 mm of where Chrome puts it. On the ninth, 97.2% of words do. That is our own measurement against Chrome for Testing 155, so treat it as a guide and check your own templates. See all nine side by side →
vellora 0.3.0, one benchmark run on a 4-core GitHub Actions Linux runner.
Simple invoiceThe open-source Sparksuite invoice template
Email receiptThe open-source Postmark receipt as published, placeholders included
Multi-page invoiceTwo pages, the header row repeated and Page X of Y in the footer
Any languageA three-page Portuguese invoice: accents and long text includedEach picture is page 1 of a real vellora 0.3.0 PDF. See the code for each →
vellora is built for documents whose HTML you control, not for printing arbitrary web pages.
Most things outside that list stop the render with the line and column, instead of handing you a broken PDF. That includes <link> stylesheets and @import: vellora never loads them, so put your CSS in a <style> tag.
VelloraUnsupportedError: Unsupported construct "css:transform" at line 1, column 11: this CSS feature is outside vellora's document subset; run `vellora fix`The full list lives on Will my template work?
No. vellora installs from npm with its renderer already built for your platform, and it runs inside your Node process. There is no browser to download, launch or keep running. If one template truly needs Chrome’s output, you can opt that template into an optional Chromium engine; nothing else changes.
macOS on Apple Silicon and Intel, and Linux on x64 and arm64 with glibc, which covers Debian and Ubuntu images such as node:22-slim. There are no Windows or Alpine/musl builds. It needs Node 20 or newer.
If it is a document you control, such as an invoice, receipt, statement or letter, there is a good chance. Put your CSS in a <style> tag, pass images and fonts as bytes, and avoid CSS grid, transforms and animations. Anything unsupported fails with the line and column instead of printing something wrong.
Very close on the documents we test: on 8 of 9, every word is within 1 mm of Chrome’s position. See all nine →
It is young. The current release is 0.3.2, and until 1.0 the API can still change between minor versions, so pin the version you test. Every change is listed in the CHANGELOG, and bugs go to GitHub issues. The same input always gives the same PDF bytes, so snapshot tests are a cheap way to catch surprises when you upgrade. To try it on a template of your own in a few minutes, start with your first PDF, then compare it with the PDF you make today.
It is free and MIT licensed. Rendering happens inside your own process and vellora makes no network requests: images and fonts come in as bytes you pass. There is no browser to sandbox or patch, and <script> tags are rejected before anything is rendered.
Ready to try it? Your first PDF in three steps →