blog
How to Generate Dynamic Reports from JSON Data
When your PDF pipeline cracks at 2 AM and customers are waiting on invoices, debugging headless Chromium is the last thing you want to do. This guide cuts to what actually matters for dynamic PDF templates in production: templates that render the same way every time, render jobs that survive queue spikes, and an API surface with clear failure modes so on-call is boring.
Updated 2026-02-24
Problem
A backend worker needs to render documents idempotently from queue events and avoid duplicate PDFs during retries.
Treat rendering as a backend job pipeline: idempotent requests, queue control, and deterministic templates.
Typst playground
A backend worker needs to render documents idempotently from queue events and avoid duplicate PDFs during retries.
Queue receipt Typst template
Sample JSON payload
#set page(paper: "a4", margin: 18mm)
#set text(font: "Inter", size: 10pt)
#let data = sys.inputs
#text(size: 22pt, weight: "bold")[#data.title]
#v(4pt)
#text(fill: rgb("#64748b"))[#data.reference + " - " + data.date]
#v(12pt)
#block(
fill: rgb("#f8fafc"),
stroke: 0.5pt + rgb("#e2e8f0"),
inset: 12pt,
radius: 4pt,
)[
#text(weight: "semibold")[#data.customer]
#linebreak()
#text(fill: rgb("#64748b"))[#data.status]
]
#v(12pt)
#table(
columns: (1fr, auto, auto),
inset: 7pt,
stroke: 0.5pt + rgb("#e2e8f0"),
[*Item*], [*Qty*], [*Amount*],
..data.line_items.map(item => (
item.name,
str(item.qty),
"$" + str(item.amount),
)).flatten(),
)Queue render receipt
Idempotent
Queue render receipt
Idempotent
Solution & copyable API code
Feed render jobs through queues partitioned by document type or priority. This prevents a noisy workload from starving critical documents. Attach stable idempotency keys per business document event so retries do not create duplicate outputs.
const response = await fetch(`${process.env.DOCUFORGE_API_URL}/v1/render`, {
method: "POST",
headers: {
"X-API-Key": process.env.DOCUFORGE_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ template_id: "tpl_how_to_generate_dynamic_reports_from_json_data", data: payload }),
});
const pdf = Buffer.from(await response.arrayBuffer());Customization tips
- Attach an idempotency key to each business event before rendering.
- Keep retry metadata outside the PDF payload so document output stays deterministic.
- Keep brand colors, spacing, and repeated footer copy in shared template variables.
- Pass customer-specific values through JSON data instead of forking the template.
- Store one approved sample payload per template so preview regressions are easy to catch.
Wichtigste Punkte
- Queue partitioning and idempotency are mandatory at scale.
- Template version IDs should be explicit in production render events.
- Monitor usage and quotas by plan and document family.
- Keep failure handling deterministic with typed error branches.
Why teams choose DocuForge for this workflow
- Render API is queue-friendly with predictable request/response envelopes.
- Usage and billing endpoints support operational visibility.
- No headless Chrome dependency in the main render engine path.
Verwandte Inhalte
FAQ
How do we avoid duplicate documents on retries?
Use business-event idempotency keys and persist render outcomes before acknowledging queue completion.
What should we put in dead-letter queues?
Jobs with non-retryable schema/template failures and jobs that exceeded bounded retry policy.
Verwandte Inhalte
Schneller liefern mit einer Template-first API
Templates live testen und dieselbe Payload direkt in Produktion verwenden.
