Skip to main content
The Cube CLI (cube) is a single-binary command-line interface for the Cube platform. Use it to create and manage deployments, deploy data model code, work with the data model Git workflow, connect GitHub repositories, tail deployment logs, and automate workspace administration from scripts and CI.
The Cube CLI works with the Cube cloud platform. It is not required for running Cube Core locally.

Installation

Linux / macOS:
Windows (PowerShell):
The installer downloads the release binary for your platform and adds it to your PATH. Set CUBE_VERSION to pin a release tag, or CUBE_INSTALL_DIR to change the install location. The CLI checks for new releases in the background and prints a notice when one is available. Update in place at any time:
Running cube with no arguments prints the installed version above the help text.

Authentication

Sign in with the browser device flow — the CLI prints a URL and a short code, opens your browser, and waits for approval:
Credentials are saved to ~/.config/cube/config.toml (Linux/macOS) or %APPDATA%\cube\config.toml (Windows). Multiple accounts are supported as named contexts (--name on login, --context on any command), and expired access tokens refresh automatically. For CI and scripts, use an API key instead:

Deploy a project

The core workflow — create a deployment, connect a database, upload your data model, and query it:
1

Create a deployment

2

Connect a database

3

Deploy your project

cube deploy hashes local files, uploads only what changed, removes remote files deleted locally (--keep-missing opts out), and triggers a single build. Pass --branch to deploy to a specific data model branch instead of the active dev-mode branch (or the deploy branch, if none is active).
4

Watch the build and query

Use the token against the deployment’s REST (JSON) API endpoint.

Import from GitHub

Connect a deployment to a GitHub repository instead of uploading files:
Connecting clones the repository into the deployment and triggers the first build.

Validate the data model

cube validate compiles a deployment’s data model and reports the compiler’s errors, exiting non-zero when there are any — so it works as a CI gate:
The compile runs where the model runs: the command asks the branch’s own Cube API for its metadata, the same call the Cube UI makes. So the model is checked against that environment’s real variables and drivers, and a branch is validated by the environment serving it — with --dev-mode, against your uncommitted working copy, before you commit it.
Pass --json for a machine-readable report (valid, errors[] with the file each was reported against, cubesCount); the exit code is the same either way.

Command reference

Run cube <command> --help for the full options of any command. List commands print tables by default; pass --json anywhere for raw JSON output, suitable for piping to jq.

Changing the Cube version

cube deployments versions lists the Cube versions a deployment can switch to — the head of each update channel, plus the older versions your account has run before:
Apply one with update. Any of 1.7.20, v1.7.20 or cubejs/cube:v1.7.20 is accepted; a version that is not on the list is rejected. The container image is resolved from the version, so there is nothing else to set:
cube deployments settings DEPLOYMENT_ID reads back every setting, including the version and channel currently in effect.

Discovering the API

cube spec prints the OpenAPI specification of the API you are logged into, so neither you nor an AI agent has to guess an endpoint’s parameters. It reads /api/v1/spec from the deployment itself, which means the contract you get is the one that build actually serves. With no arguments it lists every operation:
Pass a pattern to narrow it down. The match is case-insensitive and covers the method, path, summary, and operation id:
Add --json to get OpenAPI instead of a table. Unfiltered, that is the entire document — pipe it into a code generator or a validator. Filtered, it is a smaller but still valid document containing just the matching operations plus every schema they reference, transitively:
That last form is the one to reach for when you want an endpoint’s full parameter list: the request body’s schema is included rather than left as a $ref pointing into a document you would then have to fetch in full.
Point an agent at cube spec <topic> --json and it can construct a correct request without any hardcoded knowledge of the API.

Data model Git workflow

Edit the data model through branches without touching production:
commit pushes the dev branch’s edits to the shared branch it was forked from, and merge-to-default merges that branch into the deploy branch, rebuilds production, and deletes the branch it merged — pass --keep-branch to keep it.
Check that $DEV is set before put and commit use it. An interactive shell has no pipefail, so a failed dev-mode leaves it empty and jq still exits 0 — and put and commit accept an empty --branch, sending an empty field rather than stopping. They would then act on whatever your dev-mode session currently points at. delete-branch, the third line taking $DEV, does refuse it, so the sequence fails eventually — but only after commit has already pushed. In a script, set -o pipefail and a [ -n "$DEV" ] guard cover it.
That accounts for my-branch; exit-dev-mode and delete-branch account for what you’d otherwise leave behind. Dev mode is per-credential state, so while a session stays open every command that omits --branch targets that dev branch instead of the deploy branch, and each pass through this workflow forks another dev-… branch. Releasing and pruning before the merge also keeps the fork’s parent around until the fork is gone.
File writes (put, delete, rename) only land on a personal dev-… branch, which is what dev-mode forks and prints. Pass that name via --branch, or omit --branch to use your active dev-mode branch. Writes to any other branch are rejected by the API.create-branch --dev-mode is not a shortcut for this: it points your session at the new branch without forking, so writes to the name you gave it are rejected with “Branch … is not a dev-mode branch” even though build-status reports that branch as dev_mode. Run dev-mode on it to get a name you can write to.
enable-branch keeps a shared branch’s staging environment always active, so it stays queryable without anyone viewing the branch in the UI — useful for running tests against a branch from CI. disable-branch reverts to the default, where the environment is only active while viewed. cube data-model branches DEPLOYMENT_ID shows the current state per branch, and cube environments list DEPLOYMENT_ID --type staging lists the enabled ones with their API credentials.

dbt sync

Pull a dbt project’s models in as cubes. The repository, credential and warehouse settings come from the deployment’s dbt integration, so a sync needs only the deployment:
Each sync creates a new branch for the generated cubes and prints its name. --wait polls until the sync finishes, reporting each stage, then prints the generated files; it exits non-zero if the sync fails. Without --wait it returns a syncJobId you can follow yourself:
--ref syncs a specific branch or tag of the dbt repository instead of the one saved on the integration — which is what makes a pull-request gate meaningful, since otherwise every run would compile the tracked branch:
--ref takes a branch or tag, not a commit SHA. Syncs are not free — each one provisions a sandbox and parses the project — so prefer one per push over one per commit.

dbt sync as a CI test gate

Sync the branch under review, compile it, query it, and fail the job if any step breaks — without touching production:
With --wait --json, the sync returns the generated branch and terminal result in one document. The query must use the deployment’s deploymentUrl, and the loop must retry Continue wait responses until data arrives. Replace dbt_fct_orders.count with a measure generated by the sync.
Give the gate its own API key. Dev mode is per credential, so concurrent runs sharing a key can re-point each other’s session. The concurrency group serializes them, and the release step runs even after a failure.
Compile the personal dev-… branch returned by data-model dev-mode, not the shared branch created by the sync. The shared branch has no active runtime by default.
Keep shell: bash on the piped step so a failed cube command cannot be hidden by a successful jq process. New dbt inputs such as dbt sync --ref reject an empty value, as do required branch arguments such as data-model dev-mode and delete-branch. Existing optional flags keep their previous behavior: deployments build-status --branch '' is still accepted for a one-shot status request, but is rejected with the new --wait gate. Note that $GITHUB_HEAD_REF is only set on pull_request events; on any other trigger --ref gets an empty string, which is why the run stops there. Other existing optional --branch flags may accept an empty value for compatibility; omit them when you want the documented default. The API key needs SchemaUpdate, SchemaRead, SchemaUpdateDevBranches, and DeploymentRead for this deployment. See API keys and custom roles.
A successful gate prunes both branches it creates: the sync branch and its personal dev-… fork. Failed runs keep them for inspection. Add --remove-on-upstream to the cleanup commands if the connected Git provider branch should also be deleted.

Environment variables

Telemetry

The CLI sends anonymous usage events (command group, success/failure, version, platform). No personal data is collected; the anonymous identifier is a hash of the OS machine id. Telemetry is disabled automatically in CI, or explicitly with CUBE_NO_TELEMETRY=1 (or the legacy CUBEJS_TELEMETRY=false).