# Custom Modules in HubSpot CMS: Complete Development Guide 2026 ## Table of Contents - [Introduction](#introduction) - [What Are Custom Modules in HubSpot CMS](#what-are-custom-modules-in-hubspot-cms) - [Architecture of a Custom Module](#architecture-of-a-custom-module) - [Available Field Types](#available-field-types) - [How to Create Your First Custom Module](#how-to-create-your-first-custom-module) - [HubL: HubSpot's Templating Language](#hubl-hubspots-templating-language) - [Advanced Modules: Repeaters and Field Groups](#advanced-modules-repeaters-and-field-groups) - [Modules with Custom JavaScript and CSS](#modules-with-custom-javascript-and-css) - [Global Modules vs Section Modules](#global-modules-vs-section-modules) - [Testing and Debugging Modules](#testing-and-debugging-modules) - [Module Development Best Practices](#module-development-best-practices) - [Frequently Asked Questions](#frequently-asked-questions) - [Conclusion](#conclusion) - [References](#references) --- ## Introduction Custom modules are the most powerful component in the HubSpot CMS development ecosystem. They allow developers to create reusable content blocks that marketing teams can edit without needing code, combining the flexibility of custom development with the ease of use of the HubSpot editor. In 2026, with the consolidation of HubSpot Content Hub as a B2B content management platform, mastering custom module development is an essential skill for any developer working with HubSpot. --- ## What Are Custom Modules in HubSpot CMS A custom module in HubSpot CMS is a reusable content component made up of: - **Content fields:** The data that the marketing editor can modify (text, images, URLs, colours, etc.). - **HTML/HubL template:** The code that renders the module using the field values. - **CSS:** The module's styles. - **JavaScript:** The module's interactive functionality. - **Meta information:** The module's name, description and category. Custom modules can be used in page templates, email templates and blog templates. Once a module is created, marketing editors can drag it into the page editor and customise its content without touching the code. --- ## Architecture of a Custom Module A custom module in HubSpot CMS has the following file structure: ``` my-module.module/ ├── fields.json # Definition of the module's fields ├── meta.json # Module metadata (name, description, category) ├── module.html # HTML/HubL template of the module ├── module.css # Module styles └── module.js # Module JavaScript ``` ### fields.json The `fields.json` file defines the fields that will appear in the HubSpot editor when the module is edited. Each field has a type, name, label and configuration options. ```json [ { "id": "heading", "name": "heading", "label": "Heading", "required": true, "locked": false, "type": "text", "default": "Module heading" }, { "id": "body_text", "name": "body_text", "label": "Body text", "required": false, "locked": false, "type": "richtext", "default": "" }, { "id": "image", "name": "image", "label": "Image", "required": false, "locked": false, "type": "image", "default": { "src": "", "alt": "", "width": 800, "height": 600 } }, { "id": "cta_button", "name": "cta_button", "label": "CTA Button", "required": false, "locked": false, "type": "cta" } ] ``` ### meta.json The `meta.json` file defines the module's metadata: ```json { "label": "My Custom Module", "css_assets": [], "external_js": [], "global": false, "help_text": "Example module with text, image and CTA", "host_template_types": ["PAGE", "BLOG_POST", "BLOG_LISTING", "EMAIL"], "js_assets": [], "other_assets": [], "smart_type": "NOT_SMART", "tags": [], "is_available_for_new_content": true } ``` ### module.html The `module.html` file contains the module's HubL template: ```html
{% if module.image.src %}
{{ module.image.alt }}
{% endif %}
{% if module.heading %}

{{ module.heading }}

{% endif %} {% if module.body_text %}
{{ module.body_text }}
{% endif %} {% if module.cta_button %}
{% cta guid="{{ module.cta_button }}" %}
{% endif %}
``` --- ## Available Field Types HubSpot CMS supports a wide variety of field types for custom modules: | Field type | Description | Typical use | |---|---|---| | `text` | Single-line text | Headings, labels | | `richtext` | Rich text editor | Paragraphs, HTML content | | `number` | Number | Quantities, percentages | | `boolean` | True/False | Toggles, on/off options | | `choice` | List of options | Style variants, alignment | | `color` | Colour picker | Background colours, text | | `font` | Font selector | Custom typography | | `image` | Image | Photos, icons | | `video` | Video | Embedded videos | | `url` | URL | Links, hrefs | | `link` | Link with text and URL | Buttons, text CTAs | | `cta` | HubSpot CTA | Call-to-action buttons | | `blog` | HubSpot blog | Blog selection | | `blogpost` | Blog post | Specific post selection | | `email` | Email address | Contact forms | | `date` | Date | Event dates | | `datetime` | Date and time | Timestamps | | `tag` | Tag | Categories, tags | | `form` | HubSpot form | Lead capture forms | | `meeting` | HubSpot meeting | Meeting calendars | | `group` | Field group | Group related fields | | `repeater` | Repeatable group | Lists of elements | --- ## How to Create Your First Custom Module ### Option 1: Using HubSpot Design Manager 1. Go to **Marketing > Files and Templates > Design Manager**. 2. Click **New** and select **Module**. 3. Give the module a name and select the host type (page, email, blog). 4. Use the visual editor to add fields and edit the HTML template. ### Option 2: Using HubSpot CLI (recommended for development) HubSpot CLI allows modules to be developed locally and synchronised with your HubSpot account: ```bash # Install HubSpot CLI npm install -g @hubspot/cli # Authenticate with HubSpot hs auth # Create a new module hs create module my-module # Upload the module to HubSpot hs upload my-module.module @hubspot/my-module.module # Watch for changes and synchronise automatically hs watch ``` --- ## HubL: HubSpot's Templating Language HubL (HubSpot Markup Language) is HubSpot's templating language, based on Jinja2. It allows access to module field values, use of HubSpot system variables and application of conditional logic. ### Module variables ```html {# Access a text field #} {{ module.heading }} {# Access an image field #} {{ module.image.alt }} {# Access a link field #} {{ module.cta_link.name }} ``` ### Conditionals ```html {# Show an element only if the field has a value #} {% if module.heading %}

{{ module.heading }}

{% endif %} {# Conditional with else #} {% if module.image.src %} {{ module.image.alt }} {% else %}
{% endif %} ``` ### Loops (for repeatable fields) ```html {# Iterate over a repeatable field #} {% for item in module.items %}

{{ item.title }}

{{ item.description }}

{% endfor %} ``` --- ## Advanced Modules: Repeaters and Field Groups ### Field groups Field groups allow related fields to be grouped under the same name: ```json { "id": "card", "name": "card", "label": "Card", "type": "group", "children": [ { "id": "card_title", "name": "card_title", "label": "Card title", "type": "text" }, { "id": "card_description", "name": "card_description", "label": "Description", "type": "richtext" }, { "id": "card_image", "name": "card_image", "label": "Image", "type": "image" } ] } ``` ### Repeatable fields (Repeaters) Repeatable fields allow the editor to add multiple instances of a field group: ```json { "id": "cards", "name": "cards", "label": "Cards", "type": "group", "occurrence": { "min": 1, "max": 10, "default": 3, "sorting_label_field": "cards.card_title" }, "children": [ { "id": "card_title", "name": "card_title", "label": "Title", "type": "text" }, { "id": "card_description", "name": "card_description", "label": "Description", "type": "richtext" } ] } ``` In the HTML template, you iterate over the repeater: ```html
{% for card in module.cards %}

{{ card.card_title }}

{{ card.card_description }}
{% endfor %}
``` --- ## Modules with Custom JavaScript and CSS ### Module CSS The `module.css` file contains the module's styles. HubSpot loads them automatically when the module is present on the page: ```css .my-module { padding: 4rem 0; } .my-module__container { max-width: 1200px; margin: 0 auto; padding: 0 1.5rem; display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: center; } .my-module__heading { font-size: 2rem; font-weight: 700; margin-bottom: 1rem; } ``` ### Module JavaScript The `module.js` file contains the module's JavaScript. HubSpot loads it automatically at the end of the body: ```javascript // Access module fields from JavaScript var moduleData = {{ module | tojson }}; // Initialise module functionality document.addEventListener('DOMContentLoaded', function() { var moduleEl = document.querySelector('.my-module'); if (!moduleEl) return; // Module logic initSlider(moduleEl); }); function initSlider(container) { // Slider implementation } ``` --- ## Global Modules vs Section Modules ### Global modules Global modules are modules that are shared across multiple pages. When a global module is edited on a page, the changes are applied to all pages that use that module. They are ideal for elements such as the header, footer, announcement banners or pop-ups. To create a global module, set `"global": true` in the `meta.json` file. ### Section modules Section modules are modules that can be edited independently on each page. They are the most common modules and are used for most content blocks. --- ## Testing and Debugging Modules ### HubSpot Design Manager Preview The HubSpot Design Manager includes a preview mode that allows you to see how the module renders with different field values. ### HubSpot CLI Watch Mode HubSpot CLI's `watch` mode automatically synchronises local changes with HubSpot, enabling a very fast development cycle: ```bash hs watch --src ./my-module.module --dest @hubspot/my-module.module ``` ### HubL Debugging To debug HubL templates, use the `pprint` filter to print the value of a variable: ```html {# Print the full module value for debugging #}
{{ module | pprint }}
``` --- ## Module Development Best Practices **1. Use descriptive names for fields.** Field names should be clear and descriptive so that marketing editors understand what content to enter. **2. Provide default values.** Define default values for all fields so that the module looks good when first added to a page. **3. Use conditional fields.** Use the `visibility` property to show or hide fields based on the value of other fields, simplifying the editor interface. **4. Organise fields into groups.** Group related fields into groups to make the editor interface more intuitive. **5. Use CSS variables for colour customisation.** Instead of individual colour fields, use CSS variables so that the module respects the theme's design system. **6. Document modules.** Use the `help_text` field in `meta.json` to document the module's purpose and how to use it. **7. Version modules.** Use version control (Git) to manage changes to modules and facilitate collaboration. --- ## Frequently Asked Questions **Can I use JavaScript frameworks (React, Vue) in HubSpot CMS modules?** Yes, it is possible to use React or Vue in HubSpot CMS modules. However, for most use cases, vanilla JavaScript or jQuery are sufficient and have better performance. If you need to use React, consider using HubSpot CMS with a headless approach. **How many custom modules can I create in HubSpot CMS?** There is no official limit on the number of custom modules you can create in HubSpot CMS. **Can I share modules between different HubSpot accounts?** Yes, you can export modules from one HubSpot account and import them into another. You can also publish modules to the HubSpot Marketplace to share them with the community. **Do custom modules affect page performance?** Custom modules can affect performance if they include heavy JavaScript or CSS. Follow performance best practices: minimise CSS and JavaScript, use lazy loading for images and avoid blocking rendering. **Can I use custom modules in HubSpot emails?** Yes, you can use custom modules in HubSpot email templates. However, email templates have additional restrictions (JavaScript cannot be used, CSS must be inline). --- ## Conclusion Custom modules are the most powerful tool in the HubSpot CMS development ecosystem. By mastering their development, you can create content editing experiences that combine the flexibility of custom development with the ease of use that marketing teams need. At Emovere we specialise in the development of custom modules and themes for HubSpot CMS. If you need to develop custom modules for your HubSpot website, contact our team. --- ## References [1] HubSpot — Custom Module Documentation. https://developers.hubspot.com/docs/cms/building-blocks/modules [2] HubSpot — HubL Reference. https://developers.hubspot.com/docs/cms/hubl [3] HubSpot — CMS CLI Documentation. https://developers.hubspot.com/docs/cms/developer-reference/local-development-cms-cli [4] HubSpot — Module Fields Reference. https://developers.hubspot.com/docs/cms/building-blocks/module-theme-fields [5] HubSpot — Design Manager Overview. https://knowledge.hubspot.com/website-pages/get-started-with-the-design-manager