paste code to format, or
codefmt catches HubL bugs before HubSpot publishes them. all 28 lint rules run on every format pass: unclosed blocks, mismatched tags, unknown filters, deprecated tags, malformed module parameters, and the js-mindset traps that compile in JavaScript but break in HubL. seven rules ship one-click safe auto-fixes via the Fix and Fix (unsafe) buttons: || rewrites to or, === to ==, null to none, widget to module, and more.
HubL (HubSpot Markup Language) is the jinja2-based templating language that powers every page, email, blog post, and module in HubSpot CMS. it uses {% if %} for control flow, {{ variable }} for expressions, {# comments #} for comments, and HubSpot-specific tags like {% dnd_area %}, {% module %}, and {% macro %} for building dynamic HubSpot content.
the formatter runs purpose-built code that understands the full HubL spec: delimiter spacing, block-level tag indentation, single-line block collapse, blank lines between top-level blocks, whitespace control marker preservation ({%- and -%}), and quote normalization. content inside {% raw %} blocks is preserved exactly. codefmt auto-detects plain html and css too, so a HubSpot module's module.html or module.css formats correctly without switching tools. for a step-by-step walkthrough of what the formatter changes, read the guide to formatting and beautifying HubL.
unclosed block, mismatched block, unclosed delimiter, unexpected closer, elif after else, unexpected mid-block tag, unclosed raw block.
unknown filter, wrong filter arity, unknown global, unknown function, || instead of or, && instead of and, === instead of ==, null instead of none, backtick template literal, .forEach instead of a for tag.
duplicate block name, missing endblock, super() outside a block.
deprecated tag.
module missing path, unknown field type, malformed module params.
nested raw block, empty block, |safe without |escape, large range loop.
see the full 28-rule reference, with descriptions and severities
the only HubL tool that lints as well as formats. read why a dedicated HubSpot CMS linter matters, see how codefmt compares to other HubL tools, or how it pairs with HubSpot's VS Code extension.
HubL (HubSpot Markup Language) is a jinja2-based templating language used in HubSpot CMS for building website pages, blog templates, email templates, landing pages, and custom modules. it extends jinja2 with HubSpot-specific tags like dnd_area, dnd_section, dnd_module, and functions for accessing hubdb, blog content, and crm data.
28 rules across 6 categories. correctness: unclosed blocks (a for loop missing endfor), mismatched opening and closing tags, unexpected closers, elif after else. semantic: unknown filter names, wrong filter argument counts, unknown global identifiers with did-you-mean suggestions, unknown function names, and js-mindset traps that look right but break in HubL (|| should be or, && should be and, === should be ==, null should be none, .forEach should be a for tag, backtick template literals are not HubL). inheritance: duplicate block names, missing endblock, super() called outside a block. deprecation: widget should be module, widget_block should be module_block. module-shape: missing path, unknown field types, malformed parameters (the 'form_id 7a3' pattern where = was forgotten). hints: nested raw blocks, empty blocks, |safe without preceding |escape, large range loops above 1000 iterations. seven of these ship one-click safe auto-fixes via the Fix and Fix (unsafe) buttons.
as of 2026-05, yes. prettier-plugin-hubl from HubSpot is a formatter only, and so is the studionope.com HubL Code Formatter extension. HubSpot's official VS Code extension provides syntax highlighting and snippets but no lint. generic jinja2 template linters like djlint, and CI aggregators like super-linter that bundle existing linters, are built for django and nunjucks projects, so they don't recognize HubSpot's tags, the filter catalog, or the js-mindset traps that make HubL distinct. codefmt is the only tool that catches HubL bugs as diagnostics with one-click fixes.
the formatter handles delimiter normalization (consistent spacing inside {% %} and {{ }}), block-level tag indentation, html tag splitting and indentation (inline html tags are separated onto their own lines and properly nested), single-line block collapse for short expressions, blank line insertion between top-level blocks, whitespace control marker preservation ({%- and -%}), and quote normalization across your template.
yes. the formatter auto-detects whether your code is HubL, html, or css. if you paste plain html (like a module.html file without HubL tags) or css (like module.css), codefmt automatically formats it using Biome, a high-performance code formatter. HubL templates with embedded html are formatted by the HubL formatter, which splits inline html tags onto separate lines and indents them based on nesting.
HubL supports standard jinja2 filters like |title, |lower, |upper, |truncatewords, plus HubSpot-specific filters like |datetimeformat, |currency, |pprint, |selectattr, and |rejectattr. the formatter preserves all filter expressions and their chaining while normalizing the surrounding whitespace. the linter also validates filter names against a curated 63-filter catalog and flags unknown filters (likely typos like |datetimeformatt instead of |datetimeformat) plus wrong filter argument counts.
dnd_area, dnd_section, dnd_column, dnd_row, and dnd_module tags are treated as block-level elements and properly indented with their nested content. the formatter understands the drag-and-drop hierarchy and ensures each level is correctly indented, making complex dnd layouts much easier to read and maintain.
yes. macro definitions and their contents are properly indented as block-level structures, including any nested control flow inside them. content inside {% raw %} blocks is preserved exactly as-is. the formatter will not modify anything between raw and endraw tags, which is important for javascript snippets embedded in templates.
the formatter fully supports HubL whitespace control markers. tags using {%- -%} or {{- -}} syntax are recognized and preserved during formatting. delimiter normalization still applies inside the markers, so you get consistent spacing while retaining your whitespace trimming behavior.
absolutely. the formatter works with all HubSpot template types including email templates, blog listing and post templates, landing pages, website pages, and system templates. it correctly handles email-specific tags, blog-related loops and variables, required_email_template markers, and subscription preference tags.