Polotno generates PDFs from structured JSON rather than from HTML. A design is a schema — pages, text runs, images, and vector paths with explicit position, font, and colour — so the same template can be filled with different data and rendered thousands of times with identical layout. Generation runs through the Cloud Render API or on your own infrastructure, and the output is a real vector PDF with selectable text.
How PDF generation works
Every Polotno design is a JSON document. Generating a PDF is a matter of producing that JSON — by hand, from a template, or from a database row — and passing it to a renderer.
From the editor
import { createStore } from 'polotno/model/store';
import { jsonToPDFBlob } from '@polotno/pdf-export/browser';
const store = createStore({ key: 'YOUR_KEY' });
store.loadJSON(design);
await store.waitLoading();
const blob = await jsonToPDFBlob(store.toJSON()); // vector, selectable textFrom a server
The same schema renders without a browser session. Post the design JSON to the Cloud Render API and receive a PDF back, or run the renderer inside your own infrastructure when data residency matters. Both paths use the identical schema and produce identical output — see rendering modes for the trade-offs.
Template plus data
The pattern that makes PDF generation useful at volume is one template and many data rows. Load a template once, replace the values, render, repeat.
for (const row of rows) {
store.loadJSON(template);
store.pages[0].children
.filter((el) => el.name === 'customer')
.forEach((el) => el.set({ text: row.customer }));
await store.waitLoading();
await jsonToPDF(store.toJSON(), `./${row.id}.pdf`);
}This is variable data printing in its ordinary form: certificates, invoices, tickets, labels, personalized mailers, statements. Because the layout lives in the schema rather than in a stylesheet, the output does not drift when the data length changes — text overflow is handled by the element, not by the browser.
For programmatic template management, see create and manage templates via API.
Document generation from structured data
A document generation pipeline usually has three parts: a template, a data source, and a renderer. Polotno provides the first and third, and stays agnostic about the second.
- Template — authored in the editor by a non-developer, stored as JSON in your database.
- Data — whatever your application already holds: a row, an API response, an LLM output.
- Render — Cloud Render API or self-hosted, producing PDF, PNG, JPG, or SVG from the same schema.
Storing templates as JSON rather than as PDF blobs means they stay queryable and diffable, and a marketing user can edit one without a deploy.
Vector output, not a screenshot
Reach for @polotno/pdf-export (jsonToPDF in Node, jsonToPDFBlob in the browser) or the Cloud Render API with vector: true. The built-in store.saveAsPDF() is the raster path — it flattens each page to an image, which is not what you want for a generated document.
With the vector path, text is embedded as subsetted fonts and stays selectable and searchable; shapes stay paths. This matters for three reasons: file size stays small, the document remains accessible to text extraction, and print output scales without resampling.
Print-oriented generation supports CMYK, spot colours, bleed, and crop marks, and can target PDF/X-1a or PDF/X-4 for a commercial printer. Full detail in the PDF export docs.
What this does not cover
PDF generation here means producing a document from a design schema. It does not include filling AcroForm fields in an existing PDF, applying OCR to a scan, or compressing an existing file. If you need to open an existing PDF and change it, that is PDF editing; if you need to move a PDF into another format, that is PDF conversion.
Related reading
- Cloud Render API: pricing and request shape for managed rendering.
- Rendering modes: client-side, self-hosted, and cloud compared.
- Batch rendering at scale: production patterns for high volume.
- PDF export docs: vector output, CMYK, PDF/X.
