Data mapping

Handlebars Variables in Templates - Keep JSON and PDF in Sync

Learn variable naming, nesting, loops, and conditional patterns that prevent broken PDF output in HookPDF templates.

The single biggest reason PDF renders fail is not the API call. It is data mismatch between template variables and JSON payload.

If your template expects {{customer.name}} and your payload sends client.name, the output is incomplete even though the request itself succeeds.

This guide explains how to place Handlebars variables in a way that stays readable, testable, and stable as your templates grow.

1) Define one data contract before editing HTML

Before touching template markup, decide your payload shape.

Example contract:

JSON
{
  "invoice_number": "INV-2026-0042",
  "customer": {
    "name": "Northwind Labs",
    "address": "42 Market Street"
  },
  "items": [
    {
      "description": "Pro Plan",
      "quantity": 1,
      "line_total": "$99.00"
    }
  ],
  "total": "$108.90"
}

Only after this shape is agreed, place template variables.

2) Use explicit variable paths

Good:

HTML
<p>{{customer.name}}</p>
<p>{{customer.address}}</p>

Risky:

HTML
<p>{{name}}</p>
<p>{{address}}</p>

Why explicit paths help:

  • Fewer naming collisions
  • Easier code review
  • Faster debugging when payload changes

3) Reserve #each for true arrays only

Use #each only when the JSON field is always an array.

HTML
<tbody>
  {{#each items}}
  <tr>
    <td>{{description}}</td>
    <td>{{quantity}}</td>
    <td>{{line_total}}</td>
  </tr>
  {{/each}}
</tbody>

If items can be empty, decide UI behavior in advance (empty row, note message, or hidden section).

4) Keep formatting strategy consistent

Do not mix raw values and display-ready values randomly.

Pick one strategy per field:

  • Send display-ready strings in payload ("$108.90").
  • Or send raw numbers and transform before render request.

Most teams keep template logic minimal and send display-ready values from backend.

5) Practical variable map for an invoice

Template field Expected payload path
{{invoice_number}} invoice_number
{{customer.name}} customer.name
{{customer.address}} customer.address
{{#each items}} items[]
{{total}} total

When a render looks wrong, this table is usually enough to find mismatch in minutes.

6) Add a variable QA pass before calling API

Use this quick pass for every template update:

  1. List all {{...}} variables in template.
  2. Compare each path to a sample JSON payload.
  3. Test with realistic long values (long company name, long address).
  4. Test with 1 item and many items in items array.
  5. Run a preview render before production use.

Use this template for free now

Start with this template in HookPDF and render your first PDF for free.

Use this template free

Recommended next reads

Ready to move from prototype to production?

Create your account and generate your first API-driven PDF with HookPDF.

Get your API key