🟢 HubSpot Developer Practical Textbook — 2026 Edition Developer Edition
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.

CLI v8.0.0 (November 2025 GA)
Node.js 20 or higher required
Time required: Approximately 90 minutes
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 migratedhs uploadhs cms upload etc.
Project settings file format changedhubspot.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 uploadhs cms uploadMove under cms subcommand
hs watchhs cms watchMove under cms subcommand
hs fetchhs cms fetchMove under cms subcommand
hs createhs project createMove under project subcommand
hs deployhs project deployMove under project subcommand
hs secrets addhs project secret addMove under project secret
hs functions deployhs project deployintegrated into project deploy
hs sandbox createhs sandbox createNo change
hs authhs authNo change
hs confighs configNo change
hs openhs openNo change
hs logshs project logsMove under project
hs mcp setuphs mcp setupNewly 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
# Check Node.js version (requires 20 or higher) node -v # v20.x.x or higher # Uninstall if there is an existing CLI npm uninstall -g @hubspot/cli # install the latest version npm install -g @hubspot/cli@latest # Check version hs --version # Must be 8.x.x or higher # Help list hs help
Terminal — Initial authentication
# Interactive authentication (browser opens) hs auth # When specifying authentication information directly hs auth --portal-id 12345678 --personal-access-key "YOUR_KEY" # Check registered portals hs config list # Switch default portal 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
# Portal settings placed in the project root defaultPortal: dev-sandbox portals: - name: dev-sandbox portalId: 11111111 authType: personalaccesskey personalAccessKey: '${HUBSPOT_PAK_DEV}' # Managed by environment variables - name: production portalId: 99999999 authType: personalaccesskey personalAccessKey: '${HUBSPOT_PAK_PROD}' # Specify portal when executing command # hs cms upload --portal production
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. 1
    Create project directory Prepare a working directory and initialize a Git repository.
  2. 2
    Download themes from HubSpot To edit an existing theme hs cms fetch Get it locally.
  3. 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. 4
    Commit & push changes Version control with Git and automate deployment to production with GitHub Actions.
Terminal — Theme development flow
# Create project mkdir my-hubspot-theme && cd my-hubspot-theme git init # Download existing theme (specify design manager path) hs cms fetch "@hubspot/growth" ./themes/growth --portal dev-sandbox # or scaffold a new theme hs project create --template cms-theme-boilerplate # Use Watch mode while editing locally hs cms watch ./themes/growth "@hubspot/growth" --portal dev-sandbox # After development is complete, upload to the production portal 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
# hubspot.config.yml (placed in project root) 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 # Upload exclusion pattern 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 # main Deploy to production when merging 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_IDHUBSPOT_PAK_PRODHUBSPOT_STAGING_IDHUBSPOT_PAK_STAGING
1-7 Deploying Serverless Functions

Learn the deployment flow for Serverless Functions with HubSpot Projects.

Project configuration
# Basic directory structure for a HubSpot Project my-project/ ├── hsproject.json # Project settings ├── src/ │ ├── app/ │ │ ├── app.json # App settings │ │ └── extensions/ │ │ ├── crm-card/ # CRM card │ │ └── actions/ # custom action │ └── 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
# Create a project (interactive) hs project create # Register secret variable hs project secret add MY_API_KEY --portal dev-sandbox # Build & Deploy hs project deploy --portal dev-sandbox # Check deployment status hs project list-deploys --portal dev-sandbox # Display log in real time 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/SymptomcauseHow 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
# Run with verbose logging enabled hs cms upload ./themes/my-theme "my-theme" --debug # Check the settings hs config list # clear CLI cache hs config clear-cache # enable DEBUG mode with environment variable 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.