Skip to content

Templates

Templates define the structure and layout of pages, emails, and blog posts in HubSpot. They range from simple HTML files to complex drag-and-drop (DnD) layouts with nested module references. JetStack AI captures the full template definition — including HubL source code, layout data, and module dependencies — and reconstructs it in the destination portal with all internal paths remapped.

During import, JetStack AI retrieves:

  • Template metadata — name, path, type, label, category, and whether it is a system template
  • HubL source — the complete HubL template source code, including module tags, include/extends directives, and inline logic
  • Layout data — for DnD templates, the full layout_data JSON structure defining sections, rows, columns, and widget placements
  • Module references — all template modules referenced in the HubL source or layout data
  • Template hierarchy — parent template references (via {% extends %} directives)

HubSpot templates span several categories:

TypeDescription
PageTemplates for site pages and landing pages
EmailTemplates for marketing emails
BlogTemplates for blog listing and blog post pages
PartialReusable template fragments included by other templates
Global partialPartials available across all templates in the portal (headers, footers)
Drag-and-drop (DnD)Visual editor templates with structured layout_data

The template type determines which API endpoint JetStack AI uses and how the template content is processed during deploy.

HubL is HubSpot’s templating language. Templates contain HubL directives that reference other assets:

Module tags embed custom modules into templates:

{% module "module_name" path="/MyCompany/modules/custom-cta" %}

JetStack AI parses these tags and remaps the path parameter to the destination module’s path. The module name (first string argument) is preserved.

Templates can include other templates or extend a parent template:

{% include "/MyCompany/partials/header.html" %}
{% extends "/MyCompany/layouts/base.html" %}

JetStack AI remaps these paths to the destination template’s path after it has been deployed.

Templates that render HubDB content may contain hubdb_table_rows or hubdb_table_row function calls with table IDs. These IDs are remapped to the destination HubDB table.

Templates reference other assets that must be deployed first:

  • Parent templates — templates referenced via {% extends %} must exist before child templates
  • Template modules — custom modules referenced via {% module %} tags
  • HubDB tables — tables referenced in HubL function calls
  • Forms — forms embedded directly in template HubL code
  • Partial templates — templates referenced via {% include %} directives

JetStack AI resolves the dependency order during import and deploys templates in the correct sequence (parent templates before children, modules before templates that use them).

The entire HubL source is scanned and transformed:

  • Module path remapping — every {% module %} tag’s path parameter is updated to the destination module’s path
  • Include/extends path remapping — every {% include %} and {% extends %} directive is updated to the destination template’s path
  • HubDB ID remapping — HubDB table IDs in function calls are replaced with destination IDs

For drag-and-drop templates, the layout_data JSON is recursively parsed:

  • Cell parsing — each cell (section, row, column, widget) in the layout tree is traversed
  • Widget module references — widget path and module_id parameters are remapped
  • Widget parameters — form IDs, HubDB IDs, and other asset references within widget params are remapped
  • Nested structures — the parsing is fully recursive, handling arbitrarily deep nesting of sections within sections

Template modules define their fields with specific types (text, image, form, page, etc.). During HubL source transformation, JetStack AI detects field types to determine whether a value should be remapped. For example, a field of type form contains a form ID that needs remapping, while a field of type text does not.

HubSpot has two template-related API endpoints:

  • Layouts API — used for DnD templates that have layout_data
  • Templates API — used for coded templates (HubL source only)

JetStack AI determines which endpoint to use based on the presence of layout_data. Templates with layout data are deployed through the layouts API; all others use the templates API. If the primary endpoint fails, JetStack AI does not fall back to the other — the template types are fundamentally different.

Templates with paths matching the pattern generated_layouts/*.html are automatically identified as DnD email layouts. These are created by HubSpot’s email drag-and-drop editor and are tightly coupled to specific email content. JetStack AI handles these differently from standalone DnD page templates — they are deployed as part of the email deploy process rather than independently.

Templates with paths starting with @hubspot/ are system templates provided by HubSpot. These exist in every portal and do not need to be imported or deployed. JetStack AI automatically skips system templates during import. If a page or email references a system template, no remapping is needed since the path is identical across portals.

Known issue (fixed): The original module path extraction regex used \w+ to match module names, which does not match hyphenated module names (e.g., my-custom-module). This has been fixed to use [^'"]+, which correctly captures module names containing hyphens, dots, and other special characters. This fix applies to 3 locations in the template transformation code.

While rare, it is possible for templates to create circular include references (template A includes template B, which includes template A). JetStack AI detects circular references during dependency resolution and breaks the cycle by deploying one template without the circular include, then updating it after the other template exists.

If a deployed template shows {% module %} tags with source portal paths, the referenced module was likely not included in the import. Verify that all custom modules referenced in the template are part of the import selection. Check the dependency tree for missing module references.

If a DnD template’s layout appears broken in the destination portal:

  • Verify that all widget modules were deployed successfully
  • Check that the layout_data JSON was correctly transformed (review the deploy log for parsing errors)
  • Confirm that the template type matches the target endpoint (DnD templates must use the layouts API)

If a template fails with “parent template not found”:

  • Ensure the parent template was included in the import
  • Check that the parent template deployed successfully (it should appear earlier in the deploy log)
  • Verify the path remapping is correct — the destination path must exactly match the deployed parent template’s path

If module references containing hyphens are not being remapped, ensure you are running the latest version of JetStack AI. The \w+ regex fix (changed to [^'"]+) resolves this issue for module names like my-custom-cta or company.hero-banner.