Server Pipeline

A step-by-step breakdown of VaultPDF's 12-stage server rendering pipeline — from structure normalization to final footer injection.

Every document request passes through a deterministic 12-stage pipeline before a single byte of PDF is written. Each stage is idempotent and isolated — a failure in one stage never silently corrupts downstream output.

Execution Order Matters

Stages run sequentially in the order listed. No stage is skipped, even if its input is a no-op. This guarantees consistent output regardless of template complexity.


Pipeline Phases

The 12 stages are grouped into three logical phases:

Phase 1 — Structure

Stages 1–4 normalize the raw template tree: adaptive nesting, empty width resolution, layout consolidation, and table sanitization.

Phase 2 — Style

Stages 5–8 resolve and merge all visual rules: default style fallback, font normalization, theme merging, and theme injection.

Phase 3 — Safety & Rehydration

Stages 9–12 apply emergency layout guards and rehydrate dynamic headers, footers, and the default footer block.


Stage-by-Stage Reference

applyUniversalAdaptiveNesting

Traverses the entire template tree and wraps bare inline elements inside the correct block-level containers. This ensures every node conforms to the expected parent–child contract before any layout calculation begins.

  • Supports up to 6 levels of nesting
  • Auto-selects a layout decision per level: HEADER, TABLE, COMPACT-KV, MINI-TABLE, GROUPED-SECTIONS
  • Column Manifest — schema-driven deterministic column ordering and widths
  • Volume-aware margins — tightens vertical margins when row volume is high so tables always start on page 1

Why first?

All downstream stages assume a well-nested tree. Running this first removes an entire class of edge-case bugs from every subsequent stage.

normalizeEmptyWidths

Scans block and cell elements for missing or zero-value width declarations and assigns computed defaults based on context (column count, container width, grid mode). Prevents invisible columns and collapsed flex children.

normalizeLayouts

Reconciles conflicting layout directives — for example, a section declared as both flex and grid — and promotes the most specific rule. Also strips redundant wrapper elements that add no layout value.

sanitizeTables

Validates every table element in the template: ensures thead and tbody are present, fills missing cells to keep rows balanced, and removes illegal nesting. Malformed tables that cannot be repaired are replaced with a styled error placeholder.

Data integrity

sanitizeTables never drops data — it restructures around it. If a cell has content but an illegal parent, the content is preserved inside a corrected wrapper.

defaultStyle Fallback

Applies the document's base style sheet to every element that carries no explicit style declaration. This is the lowest-priority style pass — any property already set by the template or theme is left untouched.

Font Normalization

Resolves all font references to their embedded equivalents:

  • Named system fonts → embedded subset paths
  • Missing font families → configured fallback chain
  • Variable font axes → static instances supported by the PDF spec

Unresolvable fonts are replaced with the tenant's default body font and a warning is logged.

mergeThemeStyles

Deep-merges the active theme's style overrides on top of normalized element styles. Theme values take precedence over defaults but are overridden by explicit inline styles. The merge is non-destructive — properties not present in the theme are inherited unchanged.

applyThemeInjection

Injects theme-level constructs that cannot be expressed as per-element styles: page background color, watermarks, bleed marks, and global header/footer slot registrations. These are written directly into the PDF document metadata layer.

Emergency universalFull (passes 1–6)

A safety net that runs up to six rapid re-validation passes over the fully styled tree. Each pass checks for a specific class of late-breaking inconsistency introduced by style merging (e.g., an element whose computed width now exceeds its parent). Passes stop early once the tree is fully valid.

Performance note

In practice, well-formed templates exit after pass 1 or 2. If your document consistently reaches pass 5 or 6, review the template for conflicting width or flex declarations.

rehydrateDynamicHeader

Replaces header slot placeholders with their resolved runtime values — page numbers, document title, generation timestamp, and any custom bindings from the JSON payload. Header content is re-measured after substitution to handle variable-length values.

rehydrateDynamicFooter

Same as stage 10 but for the footer slot. Footer rehydration runs after header rehydration because some footer bindings (e.g., total page count) depend on the final header layout being settled.

Default Footer

If no footer was registered by the template or theme, this stage injects the tenant's configured default footer. If a footer is already present, this stage is a no-op. The default footer is always the last element written to the page — it is never overridden by content overflow.


Smart Rules & Hierarchy Rules Engine

Control field visibility, styling, computations, and layout per hierarchy level via hierarchyRules in the template.

Per-Level Layout Control

Each of the 6 nesting levels can independently declare its layout mode — HEADER, TABLE, COMPACT-KV, MINI-TABLE, or GROUPED-SECTIONS — without affecting sibling levels.

Field Visibility Rules

Show or hide fields based on data conditions, hierarchy depth, or tenant configuration. Rules are evaluated at render time against the live JSON payload.

Computed Fields

Define expressions inside hierarchyRules to derive values — totals, formatted dates, conditional labels — without pre-processing the JSON on the caller's side.

Style Overrides per Level

Apply fonts, colors, padding, and border rules scoped to a specific hierarchy level. Level-scoped styles take precedence over theme styles but not inline styles.

hierarchyRules Example
{
  "hierarchyRules": {
    "level1": { "layout": "HEADER", "fields": ["invoiceNumber", "date"] },
    "level2": { "layout": "TABLE", "columnManifest": ["description", "qty", "unit", "total"] },
    "level3": { "layout": "COMPACT-KV", "hideIfEmpty": true }
  }
}

See the Pipeline in Action

Use the VaultPDF playground to submit a template and inspect each pipeline stage's output in the debug trace.

On this page