Modules are the basic building blocks of HubSpot hosted pages. Knowing how they work is critical to building a successful website.

Modules are the basic building blocks of all HubSpot pages. If you're coming from a front end framework background such as Vue or React you can think of them as components.

Perhaps the best and most frightening part about them is that they are pretty darn agnostic, unopinionated, and flexible. They give you all the freedom and tools to make you the swoon of your content editing team, while also giving you enough rope to hang yourself. And the threshold between the two can be quite small.

Before we dive into building a module of our own -- let's take a few moments to break-down and understand what makes up a HubSpot Module.

HubSpot Module Anatomy 101

HubSpot modules are compsed of 5 different parts:

  • meta.json
  • fields.json
  • module.html
  • module.css
  • module.js

Depending on whether or not you're building modules using the local CLI or design tools you will notice these parts take on a slightly different appearance.

If you're working in your own text editor and are using the HubSpot CLI then you're going to notice that modules exist as a folder with a .module extension. Inside of that folder you will see the various files mentioned above. An example module might look like:

|-- beej_banner.module
  |-- meta.json
  |-- fields.json
  |-- module.html
  |-- module.css
  |-- module.js

If you're working in HubSpot's design tools, then you are looking at something that looks like this:

Module Breakdown


Meta.json is the place where you communicate with HubSpot what your module is and how HubSpot is supposed to treat it. Let's walk through some of the settings available to you in this file.


"global": false // boolean value 

This is a boolean value that will make your module a global module when set to true. Global modules will be coverd a bit more extensively in some future articles but what they sound like is pretty much what they are -- a module whose functionality and content is ... global and uniform across all instances of the module throughout the entire site.

A global module cannot have varying content or design on different pages because it is locked in and "globalized". If you want your content team to be able to edit any aspect of your module from page to page -- set this value to false.

Host Template Types

"host_template_types": ["PAGE", "BLOG_LISTING", "BLOG_DETAIL", "EMAIL"] // array

This array will determine where on what template types your module will be availbe for content editors to access. If PAGES is included in the value your module will appear on all page templates under the modules section of the page editor. If you don't want your module to show up on a certain template type simply leave it out of the array.

Note that if you are working in design tools that you will need to look at the top right corner of the module sidebar in order to edit the host template types:

Editing template types in design tools


"label": "Super Kewl Module" //string

Whatever you want your content team to be looking for when they search for your module ... That is what you should put here. Best Practice -- Keep these naming conventions consistent! It will gain you some points with your content team when they know exactly how to find the modules they are looking for. It isnt uncommon for modules to be coming from a few sources(namly multiple developers or different themes/marketplaces).

Is Available for New Content

"is_available_for_new_content": true //boolean

If you want your content to show up at all make sure this is set to true.

If you are using the CLI create command to build your module this value will default to false. You will need to edit the meta.json file and change this to true. Don't be like me and spend a solid hour trying to figure out why you cant find your module anywhere when you are quite convinced that everything was built the right way...LEARN FROM MY ERRORS!!

CSS & JS Assets

"css_assets":[{"path": "../rel/path/to/file"}], //array of path objects. 
"js_assets":[{"path": "../rel/path/to/file"}]

If your module has any depenancies, be it CSS or JS, this is one place where you can link them. There are many different ways to include additional files in a module or a template. I would recommend using this method if your file needs to be loaded regardess as to any conditions that may be present in the module.

If that last sentence doesn't make a whole lot of sense to you at this point -- dont worry. Just know files referenced here will always be loaded with your module onto the page.


This is where you craft your content editor's UI experience. Your module's field.json file is what makes your module more than just a static piece of code.

For example:

By adding a simple rich text field to your module you will give your content team the ability to add whatever copy they see fit. All you have to worry about is making sure that it's placed and styled in the correct spot.

In more advanced use cases you can even use these fields in a bit more creative fashion to conditionally render diffeerent parts of your module or even conditionally render additional fields.

Using fields in this way will allow you to create some pretty complex components for your content integration team. But be warned there is a fine balance between a module that is feature rich and one that is too complex. I will touch base on this topic a bit more in the future.

If you're building in your local environment I would also recommend donwloadin the VSCode HubSpot Extension. It makes writing these field objects a breeze.

For a full list of fields available to you, check out the field documentation here


This is where the magic happens.

Use hubl (HubSpot's templating language), HTML, and JS to bring some kind of structure and meaning to the fields that you created for your content team.

If your module doesnt have any editable fields that is still alright too. Nobody said that your module needs to have any editable featues at all. Some use cases for that might be making module that simply runs some script or makes an API call.

At the end of the day, whatever you decide to put in this section of your module will be rendered on the actual page that the module is being used on.


I think that this one is pretty self explainatory. CSS for your module goes here. 'Nuff said...

Actually, not quite. There are a few things that are helpful to know about this section.

  • CSS only -- Hubl will NOT work here. (I will talk more in future articles about what to do if you need to use hubl with your css)
  • CSS is NOT scoped to this module only.
  • If you add styles here and the same CSS selectors are referenced in other stylesheets they will conflict! Make sure to use appropriate naming conventions in your module styles to ensure you can scope your modules via class names.
  • Assuming there are no errors in your CSS -- all of your module.css files used on a page will be bundled together and minified. This way only one style sheet is loaded which handles all of the modules on your page.
  • This helps with page speed.
  • If there are errors minification and bundling will not occur.


Again, I think that this section is pretty self explainatory as well. Want your module to do cool things and be a bit more interactive. All the cool bells and whistles go here.


Assuming you followed through the whole post, you should have a pretty solid, high-level understanding on what makes up a HubSpot module. I would recommend that you try to make some of your own. Tinker with adding a field or two and try to get it all working. If you're having a difficult time getting your feet wet with this, I plan on writing a few tutorials on how to build modules in the near future.

Good luck and have fun!