Chapter 1 · CLI & Development Workflow
HubSpot CLI &
development workflow
From breaking changes to CLI v8.0.0, all command references, and building a local development environment,
Up to implementing a CI/CD pipeline using GitHub Actions. Systematically learn development workflows that can be used in practice.
1-1 CLI v8.0.0 overview and breaking changes
v8.0.0 includes an increase in the minimum Node.js version and major changes to the command system. Be sure to check existing projects.
⚠ Breaking Changes in v8.0.0:
• Node.js does not work below 18(Recommended: Node.js 20 LTS)
• Command namespace migrated:hs upload → hs cms upload etc.
• Project settings file format changed:hubspot.config.yml The structure of has been partially changed.
• Old command is deprecated warningwill be displayed and will be removed in the future.
| Old commands (v7 and earlier) | New command (v8 or later) | Changes |
hs upload | hs cms upload | Move under cms subcommand |
hs watch | hs cms watch | Move under cms subcommand |
hs fetch | hs cms fetch | Move under cms subcommand |
hs create | hs project create | Move under project subcommand |
hs deploy | hs project deploy | Move under project subcommand |
hs secrets add | hs project secret add | Move under project secret |
hs functions deploy | hs project deploy | integrated into project deploy |
hs sandbox create | hs sandbox create | No change |
hs auth | hs auth | No change |
hs config | hs config | No change |
hs open | hs open | No change |
hs logs | hs project logs | Move under project |
hs mcp setup | hs mcp setup | Newly added in v8 (MCP Server) |
How to migrate:
existing package.json If your scripts or CI/CD YAML contains old commands, please rewrite them according to the correspondence table above.
The old commands still work, butDeprecation warningwill be displayed and removed in a future version.
1-2 CLI installation and initial settings
Install from a clean state and manage settings for multiple portals.
Terminal
node -v
npm uninstall -g @hubspot/cli
npm install -g @hubspot/cli@latest
hs --version
hs help
Terminal — Initial authentication
hs auth
hs auth --portal-id
12345678 --personal-access-key
"YOUR_KEY"
hs config list
hs config set-default --portal
12345678
📁 Configuration file location
The authentication information is ~/.hubspot/ saved in the directory.
If your team manages multiple portals (production, development, sandbox), create a portal in the project root.
hubspot.config.yml By placing , you can manage portal switching on a project-by-project basis.
hubspot.config.yml
defaultPortal: dev-sandbox
portals:
- name: dev-sandbox
portalId:
11111111
authType: personalaccesskey
personalAccessKey:
'${HUBSPOT_PAK_DEV}'
- name: production
portalId:
99999999
authType: personalaccesskey
personalAccessKey:
'${HUBSPOT_PAK_PROD}'
1-3 CLI full command reference
Organize the main commands as of v8.0.0 by category.
🔐 Authentication/Settings
hs auth
Execute portal authentication. Browser opens and OAuth flow begins
hs config list
Display list of registered portals
hs config set-default
Change the default portal
hs open
Open current portal in browser
🌐 CMS development
hs cms upload <src> <dest>
Upload local files to HubSpot Design Manager
hs cms watch <src> <dest>
Monitor file changes and automatically upload (during development)
hs cms fetch <src> <dest>
Download files locally from HubSpot
hs cms fetch-module <name>
Get specific module locally
🚀 Project
hs project create
Create a new project interactively (template selection available)
hs project deploy
Deploy your project to HubSpot (including Serverless Functions)
hs project logs
Stream execution log of Serverless Function
hs project secret add
Register secret variables used in Serverless Function
🤖 AI / MCP
hs mcp setup
Configure HubSpot MCP Server as your local AI editor (new in v8)
hs mcp start
Start MCP Server locally
🏖 Sandbox
hs sandbox create
Create a new sandbox portal (Enterprise only)
hs sandbox sync
Sync data from production portal to sandbox
1-4 Building a local development environment
Build a hands-on local development flow for CMS theme modules.
-
1
Create project directory
Prepare a working directory and initialize a Git repository.
-
2
Download themes from HubSpot
To edit an existing theme hs cms fetch Get it locally.
-
3
Develop in Watch mode
Every time you save a file, it will be automatically uploaded and you can preview it in your browser.
-
4
Commit & push changes
Version control with Git and automate deployment to production with GitHub Actions.
Terminal — Theme development flow
mkdir my-hubspot-theme && cd my-hubspot-theme
git init
hs cms fetch
"@hubspot/growth" ./themes/growth --portal dev-sandbox
hs project create --template cms-theme-boilerplate
hs cms watch ./themes/growth
"@hubspot/growth" --portal dev-sandbox
hs cms upload ./themes/growth
"@hubspot/growth" --portal production
🔄 How Watch mode works
hs cms watch monitors your local directory and uploads the differences to HubSpot whenever it detects a file save.
When you work with the HubSpot preview URL open, you can see the results in near real-time each time you save.
howeverExclude images and large binaries from watchWe recommend that you upload it separately.
1-5 hubspot.config.yml detailed settings
Best practices for configuration files in team development and multi-portal environments.
hubspot.config.yml — Full configuration example
defaultPortal: dev
portals:
- name: dev
portalId:
11111111
authType: personalaccesskey
personalAccessKey:
'${HUBSPOT_PAK_DEV}'
env: development
- name: staging
portalId:
22222222
authType: personalaccesskey
personalAccessKey:
'${HUBSPOT_PAK_STAGING}'
env: staging
- name: production
portalId:
99999999
authType: personalaccesskey
personalAccessKey:
'${HUBSPOT_PAK_PROD}'
env: production
allowedExtensions:
- html
- css
- js
- json
- svg
- png
- jpg
- webp
- woff2
Difference between Personal Access Key and Personal CMS Access Key:
The "Personal Access Key" used for CLI authentication is the one in the HubSpot portal.Profile → API keyRetrieved from
It is different from Private App Token (Bearer authentication). Please manage it as a CLI-only key.
1-6 Build CI/CD with GitHub Actions
Implement a pipeline that automatically deploys to HubSpot using push as a trigger.
local development
→
PR creation
→
CI check
lint / test
→
merge into main
→
Production deployment
hs cms upload
.github/workflows/deploy.yml
name: Deploy to HubSpot
on:
push:
branches:
- main
paths:
-
'themes/**'
-
'modules/**'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version:
'20'
cache:
'npm'
- name: Install HubSpot CLI
run: npm install -g @hubspot/cli@latest
- name: Create HubSpot config
run: |
mkdir -p ~/.hubspot
cat > hubspot.config.yml <<EOF
defaultPortal: production
portals:
- name: production
portalId: ${{ secrets.HUBSPOT_PORTAL_ID }}
authType: personalaccesskey
personalAccessKey: ${{ secrets.HUBSPOT_PAK_PROD }}
EOF
- name: Deploy Theme
run: |
hs cms upload ./themes/my-theme
"my-theme" --portal production
- name: Deploy Modules
run: |
hs cms upload ./modules
"@hubspot/modules" --portal production
.github/workflows/preview.yml — PR preview
name: Deploy Preview to Staging
on:
pull_request:
branches:
- main
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version:
'20'
- run: npm install -g @hubspot/cli@latest
- name: Create config
run: |
cat > hubspot.config.yml <<EOF
defaultPortal: staging
portals:
- name: staging
portalId: ${{ secrets.HUBSPOT_STAGING_ID }}
authType: personalaccesskey
personalAccessKey: ${{ secrets.HUBSPOT_PAK_STAGING }}
EOF
- name: Deploy to Staging
run: hs cms upload ./themes/my-theme
"my-theme" --portal staging
- name: Comment PR
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '✅ Deployed to Staging completed.Check the preview.'
})
⚠ Don't forget to set GitHub Secrets:
Please register the following from "Settings → Secrets and variables → Actions" in the repository.
HUBSPOT_PORTAL_ID・HUBSPOT_PAK_PROD・HUBSPOT_STAGING_ID・HUBSPOT_PAK_STAGING
1-7 Deploying Serverless Functions
Learn the deployment flow for Serverless Functions with HubSpot Projects.
Project configuration
my-project/
├── hsproject.json
├── src/
│ ├── app/
│ │ ├── app.json
│ │ └── extensions/
│ │ ├── crm-card/
│ │ └── actions/
│ └── functions/
│ ├── my-function/
│ │ ├── my-function.functions/
│ │ │ └── index.js
│ │ └── serverless.json
│ └── package.json
└── .gitignore
hsproject.json
{
"name":
"my-project",
"srcDir":
"src",
"platformVersion":
"2023.2"
}
Terminal — project deployment
hs project create
hs project secret add MY_API_KEY --portal dev-sandbox
hs project deploy --portal dev-sandbox
hs project list-deploys --portal dev-sandbox
hs project logs --follow --portal dev-sandbox
.github/workflows/project-deploy.yml — Project CI/CD
name: Deploy HubSpot Project
on:
push:
branches: [main]
paths: ['src/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version:
'20'
- run: npm install -g @hubspot/cli@latest
- name: Setup config
run: |
cat > hubspot.config.yml <<EOF
defaultPortal: production
portals:
- name: production
portalId: ${{ secrets.HUBSPOT_PORTAL_ID }}
authType: personalaccesskey
personalAccessKey: ${{ secrets.HUBSPOT_PAK_PROD }}
EOF
- name: Install dependencies
run: npm ci --prefix src/functions
- name: Deploy Project
run: hs project deploy --portal production
1-8 Debugging and troubleshooting
A summary of common CLI errors and workarounds.
| Error/Symptom | cause | How to deal with it |
Error: Node.js version 18.x is not supported |
Old version of Node.js |
Upgrade to Node.js 20 or higher.nvm use 20 |
The portal could not be found |
Incorrect Portal ID or expired authentication |
hs config list After checking withhs auth Re-certify with |
403 Forbidden |
Personal Access Key lacks scope |
Reissue the key and give it the proper scope on your HubSpot profile page |
| Watch doesn't detect changes |
Matches an exclusion pattern or the file path is incorrect |
Specify the source path as an absolute path.--debug Display detailed log with flag |
Unexpected token in JSON |
syntax error in hubspot.config.yml |
Check with YAML validator (yamllint etc.) |
| Deployment stops midway |
File size exceeded or rate limit |
Exclude large binaries.--timeout Extend your options |
Terminal — debug options
hs cms upload ./themes/my-theme
"my-theme" --debug
hs config list
hs config clear-cache
HUBSPOT_LOG_LEVEL=debug hs cms upload ./themes/my-theme
"my-theme"
1-9 Summary of this chapter
Review before proceeding to the next chapter (CRM API Complete Guide).
✅ Chapter 1 Checklist
- Understood the breaking changes in CLI v8.0.0 (Node.js 20 required/command namespace migration)
- Checked the correspondence table between old and new commands and updated existing scripts.
hs auth Register your portal withhs config list I was able to confirm it with
- Multi-portal settings can be managed with hubspot.config.yml
hs cms watch Experienced the local development flow with
- Created deploy.yml for GitHub Actions and registered Secrets
- The CI/CD pipeline that is auto-deployed during the main merge is running.
- I built a flow that is preview deployed to Staging during PR.
About the next chapter (Chapter 2):
Learn the big picture of the HubSpot CRM API. How to use Objects API, Search API, Associations API, Batch API,
It will be explained systematically with actual code examples. We also cover rate limiting workarounds and high data processing patterns.