Posted by

Debugging HubL Templates: Practical Techniques for HubSpot CMS Developers

HubL renders on the server, so when a template misbehaves you cannot open browser dev tools and step through it. The output is simply wrong, or a section silently disappears. This guide collects practical habits for finding HubL problems quickly in templates and custom modules.

1. Print the variable before you trust it

Most HubL bugs come from assuming a variable holds something it does not. Output it directly with the pprint filter, which shows the type and structure of a value:

<pre>{{ module.cta_link|pprint }}</pre>
<pre>{{ content.tag_list|pprint }}</pre>

Check three things: is the value empty, is it a string where you expected an object (or the reverse), and does the field name match what you defined in the module's fields?

2. Show debug output only in the editor

Leaving debug markup in a live page is an easy mistake. Wrap it in the is_in_editor variable so it only appears while editing:

{% if is_in_editor %}
  <pre>{{ module|pprint }}</pre>
{% endif %}

You still need to remove it when you are done, but this reduces the risk of exposing internal data to visitors during testing.

3. Use HubL comments, not HTML comments

An HTML comment is sent to the visitor. A HubL comment is removed during rendering:

{# This note never reaches the browser #}

Commenting out blocks with {# ... #} is also a fast way to bisect a template: disable half of it, see whether the problem remains, and narrow it down.

4. Isolate loops and conditions

When a for loop renders nothing, test its input first:

{% set items = module.items %}
Count: {{ items|length }}
{% for item in items %}
  {{ loop.index }}: {{ item|pprint }}
{% endfor %}

A count of zero tells you the data is missing, not that the loop is wrong. Likewise, for an if that never fires, print the condition on its own before blaming the markup inside it.

5. Watch for scope surprises

HubSpot's documentation states that variables defined within a loop are limited to the scope of that loop and cannot be called from outside it. The reverse works: you can use a variable defined outside a loop from inside the loop. So if a value is blank after a loop, check whether it was first set inside the loop. Define it before the loop, and print it with pprint both inside and after the loop to see what it holds at each point:

{% set title = "default" %}
{% for item in module.items %}
  Inside loop: {{ title|pprint }}
{% endfor %}
After loop: {{ title|pprint }}

Source: HubSpot Developer Docs, HubL variables and macros syntax (developers.hubspot.com/docs/cms/reference/hubl/variables-macros-syntax).

6. Escape HubL when you need to show it

If you write documentation or test snippets that must display HubL literally, wrap them in {% raw %} and {% endraw %}. Otherwise HubSpot will try to evaluate them and you will chase an error that is not real.

7. Test with real query parameters

Some logic depends on the request. You can read query string values through the request object and print them while testing. Guard the output with is_in_editor, as in section 2, so the request data is never printed on the live page:

{% if is_in_editor %}
  <pre>{{ request.query_dict|pprint }}</pre>
{% endif %}

Open the page with ?debug=1 and branch on it temporarily, rather than editing the template for every experiment. Keep any such branch inside the same is_in_editor check, because a query parameter on its own can be added by any visitor.

8. Keep a fast local feedback loop

Editing in the browser design tools works, but a local workflow makes bisecting easier. With the HubSpot CLI you can develop locally, use hs cms watch to upload changes as you save, and keep your work in version control so you can revert a bad edit instantly. Check the current CLI documentation for the exact command names in your installed version, as they have changed over time.

9. A short debugging checklist

  • Print the variable with pprint and confirm its type.
  • Confirm the field name and module path are spelled exactly as defined.
  • Check whether the value exists in the editor preview versus the live page.
  • Bisect with HubL comments until the failing block is isolated.
  • Remove all debug output before publishing.

Conclusion

HubL debugging is mostly about making hidden values visible and shrinking the problem. Print data, keep debug output editor-only, bisect with comments, and use a local workflow with version control. These habits turn mysterious blank sections into quick fixes.