Last modified: August 22, 2025
Migrating an existing HubL theme to the projects framework involves restructuring the theme directory, updating file extensions, and adding necessary configuration files. This guide outlines the steps to perform this migration. After following the steps in this guide, you’ll have built and deployed a copy of your existing theme using the projects framework. You can then use the theme in your HubSpot account like any other theme, including swapping your existing pages to the new templates or using them to create new pages.
This migration will not replace your existing theme files. Instead, you’ll recreate a subset of your previous files in a new project. As a result, there are some manual steps involved for moving existing pages to the new theme.

Project setup

To build and deploy your theme on the latest version of the developer platform, you’ll need to create a project to contain your theme and its assets. After creating the project, you’ll then need to modify your theme directories and files to be compatible with the CMS React project structure requirements. Before starting the migration, your theme structure will resemble the one shown below.
theme/
├── assets/
├── modules/
├── partials/
├── styles/
├── templates/
├── fields.json
└── theme.json
1

Create an empty project

  • In the terminal, navigate to the directory where you’ll be storing your project using the cd command.
cd Documents/Dev/serverless-function-project
  • Run hs project create to create a new project.
hs project create
  • Follow the terminal prompts to create your project. For the template, select Create an empty project (no template).
After following the prompts, the project will be created with the following structure.
projectName/
├── hsproject.json
└── src/
Next, you’ll begin to build out the rest of the project to incorporate your theme.
2

Add a theme component

The src/ directory in the project is what contains the project’s various components, whether an app, theme, or CMS React module.
  • Create a new theme directory in src.
projectName/
├── hsproject.json
└── src/
  └── theme/
  • In the theme/ directory, create a theme-hsmeta.json file with the following content:
{
  "uid": "my-cool-theme",
  "type": "theme",
  "config": {
    "themePath": "my-migrated-theme",
    "secretNames": []
  }
}
FieldTypeDescription
uidStringAn internal unique identifier for the theme. Must be globally unique within the project. Can be any string up to 64 characters. Characters can be uppercase or lowercase, and can include numbers, underscores (_), dashes (-), and periods (.).
typeStringThe type of component. Must be theme.
themePathStringThe path of the directory containing the theme.json file and theme assets.
The file name theme-hsmeta.json is only for the purposes of this tutorial. You can name the file anything you’d like, as long as it ends in -hsmeta.json.
  • In addition to the -hsmeta.json file, create a new directory that you’ll be copy/pasting your original theme folder into. You can name this folder anything you’d like, but it will need to match the name set in the themePath field of -hsmeta.json.
Your project so far should resemble the following:
projectName/
├── hsproject.json
└── src/
  └── theme/
    ├── theme-hsmeta.json
    └── my-migrated-theme/

Convert your theme files

With the skeleton of your project set up, you can now copy/paste your existing theme files into the project, then modify the theme structure to fit the CMS React requirements.
1

Add your theme files

Copy the contents of your theme folder into the src/theme/my-migrated-theme/ directory. It’s recommended to copy/paste rather than move the files so that you have your original as a backup. This should result in a structure similar to the following.
projectName/
├── hsproject.json
└── src/
  └── theme/
    ├── theme-hsmeta.json
    └── my-theme/
      ├── assets/
      ├── modules/
      ├── styles/
      ├── templates/
      ├── fields.json
      └── theme.json
2

Rename HubL files and folders

To make your theme compatible with the latest version of the developer platform, you’ll need to make the following updates to your files and folders:
  • Classic HubL (i.e., non-React) modules must be in a hubl-modules directory.
  • HubL module files and templates (including partials) must be renamed to include .hubl in the file extension, except for .json files.
    • module.html becomes module.hubl.html
    • module.css becomes module.hubl.css
    • module.js becomes module.hubl.js
    • template.html becomes template.hubl.html
    • partial.html becomes partial.hubl.html
projectName/
├── hsproject.json
└── src/
  └── theme/
    ├── theme-hsmeta.json
    └── my-theme/
      ├── assets/
      ├── hubl-modules/
        ├── pricing-card.module
          ├── pricing-card.hubl.html
          ├── pricing-card.hubl.css
          ├── fields.json
          └── meta.json
      ├── styles/
        └── main.hubl.css
      ├── templates/
        ├── home.hubl.html
        └── about.hubl.html
      ├── fields.json
      └── theme.json
Because you’re renaming these files, you’ll also need to update any references in your code to match the new extensions. For example, if one of the theme’s stylesheets includes another, you would need to update the path to use hubl.css:
{% include './objects/_layout.css' %}  
{% include './objects/_layout.hubl.css' %} 
Please note:Keep in mind that these renamed files will look and function the same but will exist as new assets in your account. When swapping a page to a new .hubl.html template, existing page content will not be impacted (i.e., live website content will stay the same). However, if you want to update that content in the editor, you’ll need to manually rebuild it by adding the new module to the page and recreating the content.
3

Add a package.json file

In the directory that contains your theme.json file, add a package.json file to include the required dependencies: @hubspot/cms-components and @hubspot/cms-dev-server. You can use the example code below to get started:
{
  "name": "cms-react-theme",
  "version": "1.0.0",
  "description": "CMS React theme",
  "scripts": {
    "start": "hs-cms-dev-server .",
    "deploy": "hs project upload"
  },
  "type": "module",
  "keywords": [],
  "dependencies": {
    "@hubspot/cms-components": "latest",
    "react": "^18"
  },
  "devDependencies": {
    "@hubspot/cms-dev-server": "latest"
  }
}
With the file added, install the dependencies by navigating into the directory via the terminal, then running npm install.
4

Deploy your project to HubSpot

With these changes in place, you can upload the theme to your account by running hs project upload. This command will build and deploy both your HubL and React assets, so you’ll no longer need to use hs upload.If you would like to watch for changes (i.e., upload on save), you can use the project-specific watch command: hs project watch. However, this is less necessary when working with CMS React because you can run the local development server to view your local changes in real-time without deploying.

Running local development

With your theme recreated on the developer platform, you can preview your theme assets (modules and templates) locally using the CMS local development server. To start the local development server:
  • In your terminal, ensure you’re in the directory that contains your theme.json file.
  • Run npm run start.
  • Open http://localhost:3000 in your browser to view the local development server dashboard.
On the page, you should see your theme’s HubL modules and templates, along with high-level information about them, such as template type.
  • To view more information about a module, click the module name, then view its details in the right sidebar.
  • To view the local preview of a module or template, click View local version in the Actions column.
Screenshot showing the CMS local development server dashboard
While viewing the local version of a module or template, local changes that you save will automatically appear in the browser without needing to refresh.
Please note:The local development server will not pick up on changes made to .json configuration files. To view changes to those files during local development, you’ll need to upload them to your account first by running hs project upload.
Screen capture video showing an example of modifying a module's local CSS and HTML files and viewing the changes in the browser
As you iterate, you can send your changes to your HubSpot account with hs project upload as needed.
Please note:CMS assets built using projects will not be editable in the design manager. Instead, you’ll continue managing and building locally using hs project CLI commands.

Next Steps

Continue exploring HubSpot’s developer platform by checking out some of the following resources: