clickhousectl
clickhousectl is the CLI for ClickHouse: local and cloud.
With clickhousectl you can:
- Install and manage local ClickHouse versions
- Launch and manage local ClickHouse servers
- Execute queries against ClickHouse servers
- Setup ClickHouse Cloud and create cloud-managed ClickHouse clusters
- Manage ClickHouse Cloud resources
- Create and manage ClickPipes for data ingestion (S3, Kafka, Kinesis, Postgres, MySQL, MongoDB, BigQuery)
- Install the official ClickHouse agent skills into supported coding agents
- Push your local ClickHouse development to cloud
clickhousectl helps humans and AI-agents to develop with ClickHouse.
Installation
Quick install
|
The install script will download the correct version for your OS and install to ~/.local/bin/clickhousectl. A chctl alias is also created automatically for convenience.
cargo binstall
If you already have cargo-binstall, this pulls the prebuilt binary from builds.clickhouse.com:
npm
This installs an npm wrapper package that downloads the matching prebuilt binary from builds.clickhouse.com at install time. Both clickhousectl and chctl are exposed as commands. If you use npm install --ignore-scripts, the download is skipped — fall back to one of the other install paths.
pip
# or
# or
This installs a prebuilt wheel containing the matching clickhousectl binary. Linux (glibc and musl, x86_64 and aarch64) and macOS (Intel and Apple Silicon) wheels are published to PyPI.
From crates.io
Builds from source:
From this repo
Direct download
Prebuilt archives for each release are hosted at https://builds.clickhouse.com/clickhousectl/. Archives are named clickhousectl-{target}-v{version}.tar.gz and contain a single directory of the same name with the clickhousectl binary inside. Supported targets: x86_64-unknown-linux-musl, aarch64-unknown-linux-musl, x86_64-apple-darwin, aarch64-apple-darwin. Example: https://builds.clickhouse.com/clickhousectl/clickhousectl-aarch64-apple-darwin-v0.3.0.tar.gz.
Local
Installing and managing ClickHouse versions
clickhousectl downloads ClickHouse binaries from builds.clickhouse.com, falling back to packages.clickhouse.com (Linux) or GitHub releases (macOS) when a build isn't available there.
# Install a version
# List versions
# Manage default version
# Remove a version
local use also creates a symlink at ~/.local/bin/clickhouse pointing to the selected version's binary, so the plain clickhouse command (e.g. clickhouse local, clickhouse client) is on PATH. Pass --no-global to skip. If a regular file already exists at that path it is left alone with a warning. local remove of the active default version also clears the symlink.
local remove refuses to delete a version while a local server is running on it (it would leave the server pointing at a deleted binary), failing with the running server names. Stop the server first, or pass --force to stop the running server(s) and then remove the version.
ClickHouse binary storage
ClickHouse binaries are stored in a global repository, so they can be used by multiple projects without duplicating storage. Binaries are stored in ~/.clickhouse/:
~/.clickhouse/
├── versions/
│ └── 25.12.5.44/
│ └── clickhouse
└── default # tracks the active version
Initializing a project
init bootstraps your current working directory with a standard folder structure for your ClickHouse project files. It is optional; you are welcome to use your own folder structure if preferred.
It creates the following structure:
clickhouse/
├── tables/ # Table definitions (CREATE TABLE ...)
├── materialized_views/ # Materialized view definitions
├── queries/ # Saved queries
└── seed/ # Seed data / INSERT statements
postgres/
├── tables/ # Table definitions (CREATE TABLE ...)
├── views/ # View definitions (CREATE VIEW ...)
├── functions/ # Function / procedure definitions (CREATE FUNCTION ...)
├── queries/ # Saved queries
└── seed/ # Seed data / INSERT statements
Running queries
# Connect to a running server with clickhouse-client
Creating and managing ClickHouse servers
Start and manage ClickHouse server instances. Each server gets its own isolated data directory at .clickhouse/servers/<name>/data/.
A bare clickhousectl local server start bootstraps from zero: if no version is installed and no default is set, it installs latest and starts with it (it does not set a default, so you keep tracking latest on subsequent starts). Pin a version with --version, or set a default with local use, to opt out. Because latest tracks the rolling master build, repeat latest installs/starts do a cheap HEAD against builds.clickhouse.com and skip the ~150 MB re-download when master hasn't changed (the build's etag is cached in ~/.clickhouse/versions/.master-builds.json).
# Start a server (runs in background by default)
# List custom config files available to --config
# List all servers (running and stopped)
# Stop servers
# Remove a stopped server and its data
# Write connection env vars to .env file
Idempotent stop: server stop <name> is idempotent — stopping a server that exists but is already stopped exits 0 (it reports "is already stopped" rather than erroring), so scripts don't need to guard against it. An unknown server name still errors, so typos are caught. server stop-all likewise exits 0 when nothing is running.
Server naming: Without --name, the first server is called "default". If "default" is already running, a random name is generated (e.g. "bold-crane"). Use --name for stable identities you can start/stop repeatedly.
Ports: Defaults are HTTP 8123 and TCP 9000. If these are already in use, free ports are automatically assigned and shown in the output. Use --http-port and --tcp-port to set explicit ports.
Orphaned server recovery: If server metadata files are lost while the ClickHouse process is still running, the CLI automatically recovers them via process discovery. Running server list, server start, or any server command will detect orphaned processes belonging to the current project and bring them back under management.
Global server management: Use --global with list, stop, and stop-all to operate across all projects system-wide. server list --global shows all running ClickHouse servers with a Project column indicating which directory each belongs to.
Custom config files
Drop ClickHouse config files into ~/.clickhouse/configs/ and apply one by name when starting a server:
The named file is overlaid on top of ClickHouse's built-in defaults (it is staged into the server's config.d/ directory), so it only needs to contain the settings you want to change — you don't have to reproduce a full config. Files may be .xml, .yaml, or .yml; reference them by name with or without the extension (e.g. --config analytics or --config analytics.xml). --config takes a name within ~/.clickhouse/configs/ not a path. (--config-file remains supported as a legacy alias.)
The managed data directory (.clickhouse/servers/<name>/data/) and the HTTP/TCP ports are always forced as command-line overrides, which take precedence over the config file. This means a custom config can never break the managed server lifecycle (list, stop, remove, dotenv) regardless of its contents. Starting a server again without --config reverts it to plain defaults.
Local Postgres (Docker-backed)
When you also need a local Postgres alongside ClickHouse — e.g. for testing CDC pipelines or ingesting from Postgres — use local postgres. Each instance is keyed on (name, major version) so the same name can host multiple Postgres majors with isolated data: data lives at .clickhouse/servers/<name>-pg<major>/data/, metadata at .clickhouse/servers/<name>-pg<major>.json, and the container is clickhousectl-pg-<name>-<major>. ClickHouse paths (<name>/data/, <name>.json) stay separate, so a name can be used by both engines. Requires Docker to be installed and running.
# Pre-pull a Postgres image (optional; start will pull on demand). Supported: 17, 18 (and any sub-tag like 17-alpine, 17.0, 18-bookworm).
# Start a Postgres instance (defaults: postgres:18, port 5432, user "postgres", db "postgres")
# List everything (ClickHouse + Postgres are merged in `server list`)
# Connect with psql (uses host psql if installed; otherwise falls back to docker exec)
# Write POSTGRES_HOST/PORT/USER/PASSWORD/DATABASE into .env
# Stop / remove. Pass --version when more than one major shares a name.
local postgres start --name dev (no --version) resumes the existing instance when there's exactly one for that name; if multiple majors share the name, you'll be asked to pick. Stop preserves the container and metadata so the next start resumes it; only remove tears down the container and deletes the data directory.
Containers are tagged with clickhousectl.engine=postgres, clickhousectl.name=<name>, clickhousectl.major=<major>, clickhousectl.project=<cwd>, and created_by=clickhousectl_<version> labels. server list recovers orphaned containers belonging to the current project via these labels, so deleting .clickhouse/servers/<name>-pg<major>.json is non-destructive — the next list/start rediscovers it.
Project-local data directory
All server data lives inside .clickhouse/ in your project directory:
.clickhouse/
├── .gitignore # auto-created, ignores everything
├── credentials.json # cloud API credentials (if configured)
└── servers/
├── default/
│ └── data/ # ClickHouse data files for "default" server
└── dev/
└── data/ # ClickHouse data files for "dev" server
Each named server has its own data directory, so servers are fully isolated from each other. Data persists between restarts — stop and start a server by name to pick up where you left off. Use clickhousectl local server remove <name> to permanently delete a server's data.
Authentication
Authenticate to ClickHouse Cloud using OAuth (browser-based) or API keys. OAuth provides read-only access; API keys provide full read/write access.
If you don't have a ClickHouse Cloud account yet, clickhousectl cloud auth signup opens the sign-up page in your browser.
OAuth login (read-only)
This opens your browser for authentication via the OAuth device flow. Tokens are saved to ~/.clickhouse/tokens.json (global, shared across all directories).
Note: OAuth tokens provide read-only access. You can list and inspect resources (organizations, services, backups, etc.) but cannot create, modify, or delete them. For write operations, use API key authentication.
cloud service queryworks under OAuth too, running SQL as your own identity with read-only access — see Query API auth modes.
API key/secret (required for write operations)
# Non-interactive (CI-friendly)
# Interactive prompt
Credentials are saved to .clickhouse/credentials.json (project-local). API keys are org-scoped, so they stay per-project; OAuth tokens represent your user identity and are stored globally in ~/.clickhouse/tokens.json.
You can also use environment variables, either exported in your session:
Or place them in a .env file (only read from your current working directory):
CLICKHOUSE_CLOUD_API_KEY=your-key
CLICKHOUSE_CLOUD_API_SECRET=your-secret
Or pass credentials directly via flags on any command:
Learn how to create API keys.
Auth status and logout
Credential resolution order:
- CLI flags
.clickhouse/credentials.json- Environment variables exported in your session
- Environment variables from
.env - OAuth tokens.
Debugging which credential source was used
Pass --debug to any cloud command to print the resolved credential source (and the API URL) to stderr before the command runs. This works with and without --json.
# [debug] auth source: credentials file (.clickhouse/credentials.json)
# [debug] api url: https://api.clickhouse.cloud/v1
# ... normal output ...
Cloud
Manage ClickHouse Cloud services via the API.
Organizations
Services
# List services
# Get service details
# Create a service (minimal)
# Create with scaling options
# Create with specific IP allowlist
# Create from backup
# Create with release channel
# Create with GA request-only extras
# Start/stop a service
# Run SQL over HTTP via the Query API (no local clickhouse binary needed)
|
# Update service metadata and patches
# Update replica scaling (vertical autoscaling — fixed replica count, variable memory)
# Horizontal autoscaling — fixed memory per replica, variable replica count
# (requires the horizontal autoscaling org feature)
# Reset password with generated credentials
# Reset password with precomputed hashes
# Query endpoint management (manual — for custom roles or sharing keys with other tools)
# Private endpoint management
# Backup configuration
# Service Prometheus configuration
# Delete a service (must be stopped first)
# Force delete: stops a running service then deletes
Service Create Options:
| Option | Description |
|---|---|
--name |
Service name (required) |
--provider |
Cloud provider: aws, gcp, azure (default: aws) |
--region |
Region (default: us-east-1) |
--min-replica-memory-gb |
Min memory per replica in GB (8-356, multiple of 4). Horizontal autoscaling requires it equal to --max-replica-memory-gb |
--max-replica-memory-gb |
Max memory per replica in GB (8-356, multiple of 4). Horizontal autoscaling requires it equal to --min-replica-memory-gb |
--num-replicas |
Number of replicas (1-20) (vertical autoscaling; mutually exclusive with --min-replicas/--max-replicas) |
--min-replicas |
Min number of replicas for horizontal autoscaling (mutually exclusive with --num-replicas) |
--max-replicas |
Max number of replicas for horizontal autoscaling (mutually exclusive with --num-replicas) |
--autoscaling-mode |
Autoscaling mode: vertical (default) or horizontal. Horizontal uses fixed memory per replica (--min-replica-memory-gb equal to --max-replica-memory-gb) with a variable replica count (--min-replicas/--max-replicas); vertical uses a fixed replica count (--num-replicas) with variable memory. On service scale, combine with the target mode's flags to switch modes in one call |
--idle-scaling |
Allow scale to zero (default: true) |
--idle-timeout-minutes |
Min idle timeout in minutes (>= 5) |
--ip-allow |
IP CIDR to allow (repeatable, default: 0.0.0.0/0) |
--backup-id |
Backup ID to restore from |
--release-channel |
Release channel: slow, default, fast |
--data-warehouse-id |
Data warehouse ID (for read replicas) |
--readonly |
Make service read-only |
--encryption-key |
Customer disk encryption key |
--encryption-role |
Role ARN for disk encryption |
--enable-tde |
Enable Transparent Data Encryption |
--compliance-type |
Compliance: hipaa, pci |
--profile |
Instance profile (enterprise) |
--tag |
Attach a GA service tag (key or key=value) |
--enable-endpoint / --disable-endpoint |
Toggle GA service endpoints (currently mysql) |
--private-preview-terms-checked |
Accept private preview terms when required |
--enable-core-dumps |
Enable or disable service core dump collection |
Query API auth modes
cloud service query is the canonical way to run SQL against a cloud service — over HTTP, with no clickhouse binary and no service password required. It works with both credential modes:
- API key auth (read + write SQL): the first time
cloud service queryruns against a service without a stored key, it provisions a Query API endpoint for that service and creates a dedicated API key bound to it. The key (keyId,keySecret, andendpointId) is stored in.clickhouse/credentials.jsonunderservice_query_keys.<service-id>, alongside any user-level API key. Subsequent queries use that key. It is scoped to a single service, so it can read and write (SELECT, INSERT, DDL) against that service but cannot reach any other service in the org. Pass--no-auto-enableto fail instead of provisioning. - OAuth (
cloud auth login): the query runs as your own identity — the CLI sends your bearer token straight to the Query API, which grants read-only SQL access (SELECT and other read statements only; no INSERT, DDL, or other writes). No Query API key is provisioned or stored, and no query endpoint needs to be configured on the service. Use API key auth if you need to write.--no-auto-enablehas no effect in this mode.
Provisioning happens lazily (rather than at service create time) because the endpoint can only be bound once the service has finished provisioning, which can take several minutes — service create returns immediately instead of blocking on it.
Per-service scoping is enforced at the query endpoint binding, which is created with role sql_console_admin (read + write inside the bound service only). The API key itself has no org-level roles, so the binding is the only thing that grants it any access. cloud service delete removes the stored key from credentials.json.
Querying an idled service wakes it automatically in both auth modes — under OAuth the Query API first asks for a wake confirmation, which the CLI sends after printing a notice to stderr (the first query may take a minute while the service wakes). A stopped service is never woken: the query fails with a hint to run cloud service start.
The Query API host is derived from the API base URL per environment (api.[control-plane.]<domain> → queries.<domain>, e.g. https://queries.clickhouse.cloud for production). Set CLICKHOUSE_CLOUD_QUERY_HOST to override it.
Postgres (beta)
Manage ClickHouse Cloud managed Postgres services. All write commands require API key auth.
# List / get
# Create
# Create with HA + tags + advanced config
# Update metadata (all flags optional)
# Delete
# CA certificates
# Runtime configuration
# Password
# Read replica and PITR restore
# Lifecycle
Postgres Create Options:
| Option | Description |
|---|---|
--name |
Service name (required) |
--region |
Cloud region, e.g. us-east-1 (required) |
--size |
Instance size, e.g. m7i.2xlarge (required; server-validated) |
--provider |
Cloud provider (default: aws) |
--pg-version |
Postgres major version: 18, 17 |
--ha-type |
High-availability: none, async, sync |
--tag |
Resource tag key or key=value (repeatable) |
--pg-config-file |
Path to JSON file with a PgConfig object |
--pg-bouncer-config-file |
Path to JSON file with a PgBouncerConfig object |
Backups
ClickPipes
Manage ClickPipes for ingesting data into ClickHouse Cloud from external sources.
# List ClickPipes for a service
# Get ClickPipe details
# Start/stop/resync a ClickPipe
# Delete a ClickPipe
# Update scaling
# Get/update settings
Creating ClickPipes
Each source type has its own subcommand under clickpipe create:
# From S3 / object storage (one-shot snapshot)
# From S3 with continuous ingestion (SQS queue) and ingestion control
# --skip-initial-load: skip the initial snapshot load, only ingest new objects
# --start-after: resume ingestion after a specific object key (conflicts with --skip-initial-load)
# From Google Cloud Storage (object storage)
# From Kafka / Redpanda / Confluent / MSK
# From Amazon Kinesis
# From PostgreSQL (CDC)
# From MySQL (CDC)
# --server-id sets the replication server ID (useful when multiple pipes read
# from the same MySQL instance, or to avoid colliding with existing replicas)
# From MongoDB (CDC)
# From BigQuery (snapshot)
Use clickhousectl cloud clickpipe create <source> --help for the full list of options per source type.
Discovering a source schema (beta)
clickpipe schema-discover probes a Kafka or Kinesis source and returns the
inferred fields/types without creating a pipe. It takes the same source
connection flags as the corresponding create subcommand (minus the
destination --name/--database/--table/--column options):
# Discover schema from Kafka
# Discover schema from Kinesis
Add --json (or run as a coding agent) for machine-readable output.
Members
Invitations
Keys
Activity
JSON output
Use the --json flag to print JSON-formatted responses.
clickhousectl auto-detects coding-agent contexts (Claude Code, Cursor, Codex, Gemini CLI, Goose, Devin, and any tool that sets the standard AGENT env var) and emits JSON to stdout automatically without setting --json.
Absent fields
Cloud commands never invent values for data the API did not return. A field the API omits is shown as - in tables and human-readable output, and is left out of --json output entirely rather than emitted as null — so --json reflects exactly what the API sent.
Exit codes
Follow gh conventions:
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Error (anything not classified below) |
2 |
Cancelled (user aborted) |
4 |
Auth required (no credentials, 401/403, OAuth-only writes) |
Skills
Install the official ClickHouse Agent Skills from ClickHouse/agent-skills.
# Default: interactive mode for humans, choose scope, then choose agents
# Non-interactive: install into every supported project-local agent folder
# Non-interactive: install only into detected agents
# Non-interactive: install into every supported global agent folder
# Non-interactive: install only into detected global agents
# Non-interactive: install into specific project-local agents
# Non-interactive: install into specific global agents
Supported Skills paths
The common path .agents/skills/ is always included regardless of agent selection.
The following agents can be selected, and Skills are installed in the corresponding paths:
claude->.claude/skills/codex->.codex/skills/cursor->.cursor/skills/opencode->.opencode/skills/agent->.agent/skills/roo->.roo/skills/trae->.trae/skills/windsurf->.windsurf/skills/zencoder->.zencoder/skills/neovate->.neovate/skills/pochi->.pochi/skills/adal->.adal/skills/openclaw->.openclaw/skills/cline->.cline/skills/command-code->.command-code/skills/kiro-cli->.kiro/skills/
Supports global or project scope installation. Project scope installs Skills into the current working directory. Global scope installs Skills into the current user's home directory.
Non-interactive flags:
--agentname a specific agent to install Skills for, can be repeated--globaluse global scope; if omitted, project scope is used--allinstall Skills for all supported agents--detected-onlyinstall Skills for supported agents that were detected on the system
Self-update
clickhousectl can update itself to the latest release:
# Update to the latest version
# Check for updates without installing
The CLI checks for updates in the background (at most once per 24 hours) and caches the result. When a newer version is available, a one-line notice is printed to stderr at the end of every command that produces human-readable output. JSON output (--json or a detected coding agent) is never affected, so machine consumers stay clean. Running clickhousectl update clears the cached notice.
Telemetry
clickhousectl collects anonymous usage data to help us understand which commands matter and improve the CLI. Full details: https://clickhouse.com/docs/concepts/features/interfaces/cli#telemetry.
Each event contains exactly:
- the command path (e.g.
local start) - the names of the flags passed (e.g.
json,org-id) — never flag values, never positional arguments - how the invocation ended and its exit code
- the CLI version, OS, and architecture
- whether it ran in CI (
CIenv var) - whether it ran under a detected coding agent, and if so which one (e.g.
claude-code)
There is no install ID, no device ID, and no fingerprinting of any kind. The payload is built from the clap command definitions rather than the raw command line, so leaking an argument value is structurally impossible — the code that builds the event has no access to values at all.
Nothing is ever sent before you have seen the notice or explicitly enabled telemetry with clickhousectl telemetry enable: the first run prints a one-time notice to stderr, records that it was shown in ~/.clickhouse/telemetry.json, and sends nothing. Sending starts from the following run — or immediately if you opt in by running telemetry enable, which is explicit consent and skips the notice. The send happens in a short-lived detached process, so command latency is unaffected even when the endpoint is unreachable.
Opt out any of these ways:
# Persistently, per machine
# Check the current state
# Per environment/shell (https://consoledonottrack.com)
To see exactly what would be sent without sending it, set CHCTL_TELEMETRY_DEBUG=1 — the payload is printed to stderr and nothing leaves the machine.
Distribution packagers can compile telemetry out entirely (including the telemetry subcommand) with cargo build --no-default-features.
Cloud integration testing
Cloud API integration is tested against a real ClickHouse Cloud workspace via the library crate. All changes to cloud commands must pass CI testing before merge. Tests live in three binaries, each a single #[tokio::test] lifecycle:
tests/integration_test.rs— ClickHouse service CRUD + service-scoped endpointstests/integration_postgres_test.rs— Postgres service CRUDtests/integration_org_test.rs— org-scoped endpoints (members, invitations, roles, activity, prometheus, private endpoint config)
Required environment variables:
# Required for the org integration suite (members + invitations need a
# second user in the test org); optional otherwise.
Run a suite:
By default, any failed check fails the run. To keep going after non-blocking capability failures and collect them in a summary at the end, set:
Requirements
- macOS (aarch64, x86_64) or Linux (aarch64, x86_64)
- Cloud commands require a ClickHouse Cloud API key