Document Automation
Column Mapping for PDF Templates: Stop Renaming Headers Forever
- column mapping
- template
- Google Sheets
- PDF generation
- DocForge
Why ops keeps breaking your "perfect" template
You launch the PDF template. Everyone loves it. Two weeks later finance inserts a column between B and C "just for the new tax field," every invoice now ships with the wrong total, and the spreadsheet owner is blamed for "breaking the export."
This is not a finance problem; it's a binding problem. The template referenced column letters (B, C) instead of the meaning of the data. The fix is header-based mapping with explicit, versioned bindings.
Three mapping models, only one survives
- Positional (avoid): placeholder reads
B2; breaks on any column insertion. - Header-keyed (better): placeholder reads
row["Customer Name"]; survives reorder but breaks on rename. - Mapped (best): a stored mapping links
{{customer_name}}→ headerCustomer Name; rename the header, update the mapping once, all templates keep working.
The mapping editor needs three jobs
- Discover headers: read the first non-empty row of the selected sheet and list candidates.
- Bind placeholders: for each template variable, pick the header (or constant) that fills it.
- Detect drift: warn when a stored binding references a header that no longer exists; offer the closest match by fuzzy distance.
Type coercion is part of mapping
A column that looks like "1,234.56" might be a string in the sheet but needs to be a number in the PDF for formatting and totals. The mapping carries a type per variable:
- number with locale-aware parsing (comma vs dot decimal).
- date with explicit input/output format—never let JS auto-parse.
- currency bundles amount + currency code; downstream formatting picks the right symbol.
- boolean normalizes "yes/no", "true/false", "1/0".
Conditional sections kill duplicated templates
Teams clone the template "for the version with shipping" or "for the EU version." Each clone drifts. A robust mapping supports flags that toggle entire sections:
{{#if has_shipping}} ... {{/if}}reads a boolean column.{{#each line_items}} ... {{/each}}repeats a nested table.{{#if region == "EU"}} ... {{/if}}shows the VAT block only when needed.
Mapping versioning saves audits
The mapping itself should be versioned—stored alongside the template with a hash. When a PDF is generated, the run log records template version and mapping version. If a regulator asks "why did this invoice look different in March vs. May?", you have the answer.
Real-world test cases to add
- Insert a column between two existing ones—batch must still work.
- Rename a header to a typo—generator warns instead of silently shipping wrong data.
- Add 1,000 rows with mixed locales—numbers and dates format correctly.
- Hide a column—generator still resolves it.
Where DocForge fits
DocForge uses header-keyed, versioned mapping with type coercion, conditional sections, and drift detection—so the day finance reorders the sheet, the batch keeps shipping. Install on Google Workspace and stop apologizing for "the export."
Related articles
Document Automation
Google Sheets to PDF in Bulk: The Complete 2026 Guide
Stop exporting rows one by one. Learn how to turn a Google Sheets tab into hundreds of branded PDFs—invoices, quotes, contracts—with template variables, auto numbering, and Drive delivery.
Document Automation
Invoice Numbering Without Pain: Automation for Google Sheets
Sequential, gap-free, audit-ready invoice numbers from Google Sheets—without the duplicate disasters every finance team has seen.
Document Automation
ZUGFeRD & Factur-X EU Invoices from Google Sheets
Hybrid PDF/XML invoicing is mandatory across the EU for B2G and growing for B2B. Generate compliant ZUGFeRD/Factur-X invoices straight from Google Sheets—without leaving Workspace.