Skip to content
Stand with Ukraine flag

Getting started with ThingsBoard CLI

ThingsBoard CLI (thingsboard, alias tb) lets you build and manage your ThingsBoard solutions from the terminal, treating your setup as code you can version, review, and ship to any environment. There are two ways to work with it:

  • With an AI agent. Describe what you want in plain English and your AI coding agent (Claude Code or Antigravity) builds a new solution, evolves an existing one, or makes a targeted change for you — see how to manage IoT solutions with ThingsBoard CLI.
  • Yourself. Run the CLI commands directly for full, precise control — interactively, or in scripts, CI pipelines, and one-off tasks.

You need a ThingsBoard account: ThingsBoard Cloud or a self-hosted ThingsBoard Professional instance.

  1. Install uv.

    uv is a fast Python package manager that handles the CLI’s virtual environment for you.

    Terminal window
    curl -LsSf https://astral.sh/uv/install.sh | sh

    See the uv installation guide for platform-specific options.

  2. Install the CLI.

    Terminal window
    uv tool install thingsboard-cli

    This installs the thingsboard command and its tb alias on your system.

  3. Verify the installation.

    Terminal window
    tb --version

Before the CLI can talk to ThingsBoard, it needs a connection: which instance to reach and how to authenticate. You define that as a profile — a URL plus credentials, saved under a name you choose. The active profile determines which instance your commands target.

Create a profile with the interactive wizard:

Terminal window
tb config

The wizard walks you through a few prompts:

ThingsBoard URL [https://thingsboard.cloud]:
Auth method [api_key]:
API Key: ********
Profile name: cloud
  • ThingsBoard URL. Defaults to https://thingsboard.cloud — press Enter to accept, or enter your own URL, like https://eu.thingsboard.cloud for Cloud EU or your self-hosted host.
  • Auth method. Defaults to api_key — press Enter to accept. This is the recommended method. The alternative jwt saves your username and password to the profile file in plaintext; the CLI warns you and recommends API key auth instead.
  • Credentials. With api_key, enter your API key — create one under Account ⇾ Security ⇾ API keys (see API Keys). With jwt, the wizard prompts for your username and password instead.
  • Profile name. A short alias for this connection, so you can tell your instances apart and target them by name (cloud, prod, staging).

For scripting, skip the wizard:

Terminal window
tb config set --url <url> --api-key <key>

Profiles are additive — create as many as you need and switch between them:

Terminal window
tb config list # show all profiles
tb config use prod # switch the default profile
tb config add staging --url https://... --api-key ...

Pass --profile <name> to any command to override the active profile for that call.

A project is your local workspace for designing and managing ThingsBoard solutions — the folder where the CLI reads and writes entity files, and where your agent builds solutions. To start one, create a new directory (or open an existing folder) and run tb init inside it; that folder becomes the project root.

Terminal window
mkdir my-iot-project && cd my-iot-project && tb init

ThingsBoard CLI works with both Claude Code and Antigravity, so you can scaffold the project for whichever agent you have. tb init detects the agent CLIs you have installed and asks which format to scaffold:

Detected Claude Code.
Unpack skills and agents for which format? (use ↑/↓ arrows, Enter to select)
❯ claude (detected)
antigravity
both
  • claude — writes a .claude/ directory with the bundled skills and agents.
  • antigravity — writes .agents/ and an AGENTS.md file.
  • both — writes both layouts.

Pass --agent-format claude, --agent-format antigravity, or --agent-format both to skip the prompt in CI. Your choice is saved in thingsboard.json.

tb init scaffolds the project:

my-iot-project/
asset-profiles/ # entity folders — one JSON file per entity
assets/
customers/
dashboards/
device-profiles/
devices/
entity-groups/
extension/ # scaffold for a custom backend extension
roles/
rule-chains/
solutions/ # one subdirectory per solution
tasks/ # telemetry emulators and calculated field reprocessing jobs
users/
.claude/ # bundled skills and agents (or .agents/ + AGENTS.md for Antigravity)
.git/ # git repository (initialized if the folder isn't already in one)
thingsboard.json # project config — records the mode and the agent format you chose
.gitignore
  • Entity folders. The root-level devices/, dashboards/, assets/, and the rest hold entities that don’t belong to any solution.
  • solutions/. A solution is a self-contained collection of devices, dashboards, alarm rules, and other entities that work together to solve one business need — a smart house, a fleet, a factory line. Each lives in its own subdirectory here. A single project can hold many solutions, and the same solution can be deployed to multiple ThingsBoard targets (dev, staging, prod) without any changes.
  • extension/. A scaffold for a custom backend extension for behavior that ThingsBoard can’t express natively.

Launch your agent from the project directory:

Terminal window
claude --model sonnet

The bundled skills load automatically, so the agent is ready to design and deploy solutions right away. From here, learn how to manage IoT solutions with ThingsBoard CLI.

Mode is a per-project setting:

Terminal window
tb config mode local # default: write commands save to project files; nothing reaches ThingsBoard until tb push
tb config mode remote # write commands call the ThingsBoard API immediately

Add --remote to force a single command to call the API without changing the project’s mode.

The CLI’s built-in help is always current and is the canonical reference for every command:

Terminal window
tb --help # top-level command groups
tb device --help # subcommands in a group
tb device save --help # flags for one command

Append -H (or --help-verbose) to any command that maps to a ThingsBoard API method to see the full request schema, including which fields are required and which are read-only:

Terminal window
tb device save -H

Drive the CLI yourself with the command groups below.

Every entity type has its own group with the same list / save / delete shape (tb device, tb dashboard, tb asset, tb customer, tb rule-chain, tb calculated-field, etc.).

Terminal window
# List devices
tb device list
# Create a device from a JSON body
tb device save --json '{"name": "Sensor-01", "type": "Temperature Sensor"}'
# Or use shorthand flags for common fields
tb device save --name Sensor-02 --type "Temperature Sensor"
# Save server-scope attributes on an entity
tb attributes save DEVICE <entity-id> --scope SERVER_SCOPE --json '{"firmwareVersion": "1.0.3"}'

In local mode tb <entity> save writes one JSON file per entity into the matching entity folder, and nothing reaches ThingsBoard until you run tb push. In remote mode, the entity is persisted to your instance immediately.

Each solution lives under solutions/<slug>/, and solutions can only be built in local mode.

Terminal window
tb solution new smart-building # create a solution
tb solution list # list solutions in the project
tb device save --solution smart-building --name Sensor-01 --type "Temperature Sensor"

To save an entity under a solution, add --solution <name> to the command — it works from anywhere in the project.

Terminal window
tb validate # dry-run root entities against the target
tb validate smart-building # dry-run one solution
tb push smart-building # deploy a solution (omit the name to deploy root entities)
tb push smart-building --run-tasks # also run telemetry emulators and calculated field backfill

tb push --run-tasks does the regular push and then runs two extra steps:

  • Telemetry emulators. The CLI writes synthetic telemetry for the devices your agent set up emulators for, so dashboards have something to display.
  • Calculated field backfill. The CLI replays historical inputs through each calculated field expression so derived values are populated for the time range covered by the emulators.

Both steps are safe to omit on later pushes once the data exists — they are most useful on the very first push to a fresh tenant.

The same solution can be deployed to multiple ThingsBoard environments by pushing it under different config profiles:

Terminal window
tb push smart-building --profile dev
tb push smart-building --profile staging
tb push smart-building --profile prod

The CLI writes no state files to your project — push to the same target twice and existing entities are updated, not duplicated. Develop and test against dev, promote to staging once you’re happy, and ship to prod with the exact same files.

tb pull is the inverse of push: it fetches the current server state and rewrites the matching JSON files on disk. Reach for it when someone tweaked a dashboard in the UI, when you want a fresh local copy of what’s running on staging, or when you need to bring a server-created entity into the project.

Terminal window
tb pull # refresh every locally-tracked entity in the current solution
tb pull --solution smart-building # the same, with the solution named explicitly
tb pull dashboard --all # refresh every dashboard in the current solution
tb pull device <uuid> # fetch a single entity by its server-internal UUID
tb pull device <uuid1> <uuid2> # …or several at once

The UUID form is how you pick up entities that exist on the server but aren’t in the project yet — pass the internal ID and the CLI writes a fresh file under the right directory.

A few flags worth knowing:

  • --dry-run prints the planned writes (created / updated / renamed) without touching disk.
  • --with-credentials includes device credentials in the pulled files. Off by default; opt in only when you want them committed alongside the device JSON.
  • --force skips the safety check that aborts when target files have uncommitted git changes.

By default, tb pull refuses to overwrite files with uncommitted local changes, so it never silently clobbers work in progress. Commit, stash, or pass --force to proceed.

To bring a solution that already runs in ThingsBoard under CLI management, use the interactive pull to select exactly which entities to import:

Terminal window
tb pull -i

The CLI opens a terminal UI where you browse your tenant across all entity types, including entity groups. Select the entities you want and press Enter to import them.

  • Press space to toggle selection on an individual entity.
  • Press m on an entity group to select all entities in that group.
  • Press a to select all entities in the current view.

Use owner:<name> or server:<query> in the search bar to filter by owner or run a server-side query. Once pulled, the entities land in your project files and stay in sync on the next tb push.

Help improve the CLI with tb feedback — share your experience with the tool:

Terminal window
tb feedback

Install completion once and restart your terminal:

Terminal window
tb --install-completion bash # bash
tb --install-completion zsh # zsh
tb --install-completion fish # fish
  • tb push has no automatic rollback. If you push a broken solution, fix it locally and push again.
  • Entity identity is tracked server-side by external ID. UI edits to project-managed entities are overwritten on the next tb push unless you tb pull them back first. Brand-new entities created outside the CLI can also be brought into the project with tb pull.

“No entities to push”

The solution or project root has no entity files yet. Create some — ask your agent, or run tb device save (or another entity command) — then push again.

“Commands target the wrong solution”

Scope commands with --solution <name>; the flag works from anywhere in the project and is more reliable than relying on the current directory.