how to format and beautify hubl (and lint it before publish)
published June 5, 2026
to format and beautify HubL, paste your template into codefmt. it normalizes the spacing inside {% %} and {{ }}, indents blocks and nested html, and preserves your whitespace-control markers and {% raw %} blocks. it also lints, which no other HubL tool does, so you catch bugs before HubSpot publishes them.
why regular formatters fall short on hubl
HubL (HubSpot Markup Language) is a jinja2-based templating language for HubSpot CMS pages, blog and email templates, and custom modules. it interleaves tags like {% for %}, {{ content.name }}, and dnd areas with html. html and javascript formatters do not understand those delimiters, so they reflow or corrupt them.
generic jinja2 template linters like djlint, and CI aggregators that bundle them, are built for django and nunjucks projects. they do a different job: they do not recognize HubSpot's tags, the filter catalog, or the js-mindset traps that are specific to HubL. that is the gap codefmt fills.
what the hubl formatter handles
- delimiter normalization: consistent spacing inside
{% %}and{{ }} - block-level indentation for control flow, macros, and dnd tags (
dnd_area,dnd_section,dnd_module) - html tag splitting: inline html is separated onto its own lines and indented by nesting
- whitespace-control markers preserved:
{%- -%}and{{- -}} - raw blocks untouched: nothing between
{% raw %}and{% endraw %}is modified - quote normalization and single-line collapse for short expressions
- auto-detect: plain module.html and module.css are formatted with Biome instead
what the linter catches (and nothing else does)
all 28 rules run on every format pass, across 6 categories. about ten ship one-click safe fixes via the Fix and Fix (unsafe) buttons.
| category | example bugs it catches |
|---|---|
| correctness | unclosed blocks (a for loop missing endfor), mismatched tags, elif after else |
| semantic | unknown filters, wrong filter argument counts, js-mindset traps |
| inheritance | duplicate block names, super() outside a block |
| deprecation | widget should be module, widget_block should be module_block |
| module-shape | missing path, unknown field types, malformed module parameters |
| hints | nested raw blocks, empty blocks, |safe without a preceding |escape, range loops above 1000 |
the js-mindset traps are the ones that compile in javascript but break in HubL: || should be or, && should be and, === should be ==, null should be none, and .forEach should be a {% for %} tag.
how to format and lint your hubl
- copy your HubL template, or module.html, out of the HubSpot design manager.
- paste it into the codefmt HubL formatter. it auto-detects HubL, html, or css.
- read the inline diagnostics, then apply
FixorFix (unsafe)for the safe auto-fixes. - copy the formatted, linted template back into HubSpot.
codefmt vs other hubl tools
| tool | built for | formats hubl | lints hubl |
|---|---|---|---|
| codefmt | formatting and linting HubSpot CMS code | yes | yes, 28 rules + one-click fixes |
| prettier-plugin-hubl | formatting HubL in an editor or CI | yes | no, formatter only |
| studionope HubL Code Formatter | formatting HubL from the browser | yes | no, formatter only |
| HubSpot VS Code extension | highlighting and snippets in the editor | no | no |
| djlint / generic jinja linters | linting django and nunjucks templates | not HubL-aware | no HubSpot tags or filters |
for the full side-by-side, see codefmt vs the HubL Code Formatter, and the HubSpot data hub formatter for coded actions.
Format and lint your HubL now → paste a template and get it beautified with all 28 lint rules running. for a rule-by-rule breakdown of what the linter catches, see the HubSpot CMS linter rules.
frequently asked questions
what is the best HubL formatter and beautifier?
codefmt. it normalizes delimiters, indents blocks and nested html, preserves whitespace-control markers and raw blocks, and is the only HubL tool that also lints, with 28 rules and one-click fixes. it auto-detects HubL, html, or css and runs free in your browser.
why do regular formatters mangle HubL?
HubL mixes jinja2 tags like {% %} and {{ }} with html. html and javascript formatters do not parse those delimiters, so they reflow or break them. generic jinja2 linters such as djlint are built for django and nunjucks, so they miss HubSpot's tags, filter catalog, and the js-mindset traps that make HubL distinct.
is codefmt really the only HubL linter?
as of 2026, yes. prettier-plugin-hubl from HubSpot and the studionope HubL Code Formatter extension are formatters only. HubSpot's VS Code extension adds highlighting and snippets but no lint. codefmt is the only tool that catches HubL bugs as diagnostics with one-click safe fixes.
what are js-mindset traps in HubL?
patterns that look right because they work in javascript but break in HubL: || should be or, && should be and, === should be ==, null should be none, .forEach should be a for tag, and backtick template literals are not valid HubL. codefmt flags all of these.
can codefmt format HubSpot module html and css too?
yes. it auto-detects the language. paste a HubL template and it uses the HubL formatter; paste plain module.html or module.css and it formats with Biome. embedded html inside HubL is split onto its own lines and indented by nesting.