clickhousectl (chctl) is the official CLI for ClickHouse and Postgres, locally and in ClickHouse Cloud.
With clickhousectl you can:
- Install, run, and query ClickHouse locally
- Run Docker-backed Postgres instances for local development
- Create a ClickHouse Cloud account and authenticate from the terminal
- Create and manage ClickHouse and Postgres services in ClickHouse Cloud
- Run SQL against local and cloud ClickHouse services
- Create and manage ClickPipes for data ingestion (S3, Kafka, Kinesis, Postgres, MySQL, MongoDB, BigQuery)
- Install the official ClickHouse agent skills into supported coding agents
- Move local ClickHouse development to ClickHouse Cloud
clickhousectl helps humans and coding agents develop with ClickHouse and Postgres.
curl -fsSL https://clickhouse.com/cli | shThe 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.
If you already have cargo-binstall, this pulls the prebuilt binary from builds.clickhouse.com:
cargo binstall clickhousectlnpm install -g clickhousectlThis 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 install clickhousectl
# or
pipx install clickhousectl
# or
uv tool install clickhousectlThis 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.
Builds from source:
cargo install clickhousectlcargo install --path crates/clickhousectlPrebuilt 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.
This README focuses on common tasks and representative examples. The CLI help is the complete, version-matched command reference: start with clickhousectl --help, then use help at any level, such as clickhousectl cloud postgres --help or clickhousectl local server start --help.
A bare start bootstraps the local environment, including installing ClickHouse if needed:
clickhousectl local server start
clickhousectl local client --query "SELECT version()"Start Docker-backed Postgres and query it with psql through the CLI. A random password is generated unless one is provided:
clickhousectl local postgres start
clickhousectl local postgres client --query "SELECT version()"Create an account, then authenticate with browser-based OAuth for read-only access or an API key for read/write access:
# Create a ClickHouse Cloud account
clickhousectl cloud auth signup
# Opens an OAuth login in the browser (read-only)
clickhousectl cloud auth login
# Or use API keys non-interactively (read/write)
clickhousectl cloud auth login --api-key X --api-secret Y
clickhousectl cloud org listCreating or changing Cloud resources requires an API key with the appropriate role. Create an API key. You can also export CLICKHOUSE_CLOUD_API_KEY and CLICKHOUSE_CLOUD_API_SECRET or add them to your .env file.
Create and query a ClickHouse Cloud service:
clickhousectl cloud service create \
--name my-clickhouse \
--provider aws \
--region us-east-1
# Repeat until the service state is `running`
clickhousectl cloud service get <service-id>
clickhousectl cloud service query \
--name my-clickhouse \
--query "SELECT version()"service create returns an initial password, which the CLI prints once; store it securely. SQL through service query does not require that password.
Create a managed Postgres service:
clickhousectl cloud postgres create \
--name my-postgres \
--provider aws \
--region us-east-1 \
--size c6gd.xlarge \
--pg-version 18
# Repeat until the Postgres service state is `running`
clickhousectl cloud postgres get <postgres-id>
# If create returned a connection string, assign it securely and query with psql
psql "$POSTGRES_CONNECTION_STRING" --command "SELECT version()"postgres create returns an initial password, which the CLI prints once; store it securely.
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.
# Manage default version
clickhousectl local use latest # Latest master build; installs if needed and creates ~/.local/bin/clickhouse
clickhousectl local use 26.8 # Latest 26.8.x.x (installs if needed)
clickhousectl local use 26.8.1.1760 # Exact version
clickhousectl local use latest --no-global # Set default but don't touch ~/.local/bin/clickhouse
clickhousectl local which # Show current default
# Install a version
clickhousectl local install latest # Latest master build
clickhousectl local install 26 # Latest 26.x.x.x
clickhousectl local install 26.8 # Latest 26.8.x.x
clickhousectl local install 26.8.1.1760 # Exact version
# List versions
clickhousectl local list # Installed versions
clickhousectl local list --remote # Available for download
# Remove a version
clickhousectl local remove 26.8.1.1760
clickhousectl local remove 26.8.1.1760 --force # Stop running servers on this version firstlocal 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 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/
│ └── 26.8.1.1760/
│ └── clickhouse
└── default # tracks the active version
clickhousectl local initinit 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
# Connect to a running server with clickhouse-client
clickhousectl local client # Connects to "default" server
clickhousectl local client --name dev # Connects to "dev" server
clickhousectl local client --query "SHOW DATABASES" # Run a query
clickhousectl local client --queries-file schema.sql # Run queries from a file
clickhousectl local client --host remote-host --port 9000 # Connect to a specific host/portStart 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)
clickhousectl local server start # Named "default" (installs latest if nothing is set up yet)
clickhousectl local server start dev # Named "dev"
clickhousectl local server start --version latest # Use a specific version (installs if needed, doesn't change default)
clickhousectl local server start --foreground # Run in foreground (-F / --fg)
clickhousectl local server start --no-wait # Return after spawning without waiting for readiness
clickhousectl local server start --http-port 8124 --tcp-port 9001 # Explicit ports
clickhousectl local server start --config analytics # Apply a custom config (see "Custom config files" below)
# List custom config files available to --config
clickhousectl local server configs
# List all servers in this project (ClickHouse and Postgres, running and stopped)
clickhousectl local server list
clickhousectl local server list --global # List running ClickHouse servers across all projects
# Stop servers
clickhousectl local server stop # Stop "default"
clickhousectl local server stop dev # Stop by name
clickhousectl local server stop default --global # Stop from any project
clickhousectl local server stop default --global --project /path/to/project # Disambiguate
clickhousectl local server stop-all # Stop all ClickHouse and Postgres servers in this project
clickhousectl local server stop-all --global # Stop all ClickHouse servers system-wide
# Remove a stopped server and its data
clickhousectl local server remove # Remove "default"
clickhousectl local server remove test # Remove by name
# Write connection env vars to .env file
clickhousectl local server dotenv # From "default" server → .env
clickhousectl local server dotenv --name dev # From "dev" server → .env
clickhousectl local server dotenv --local # Write to .env.local instead
clickhousectl local server dotenv --local --user default --database mydb # Include user and databaseStopping a server preserves its data and identity metadata, so it remains visible in server list with a stopped status. Version and ports are shown only while running because they are resolved again on each start. Starting the same name resumes the existing data directory.
Server naming: Without a name, the first server is called "default". If "default" is already running, a random name is generated (e.g. "bold-crane"). Pass a name positionally 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.
Readiness: Background starts wait up to 30 seconds for the HTTP health check and TCP port before reporting success, so a following local client command can connect immediately. Startup failures point to .clickhouse/servers/<name>/server.log. Use --no-wait for fire-and-forget startup.
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.
Drop ClickHouse config files into ~/.clickhouse/configs/ and apply one by name when starting a server:
mkdir -p ~/.clickhouse/configs
cat > ~/.clickhouse/configs/analytics.xml <<'EOF'
<clickhouse>
<query_log>
<database>system</database>
<table>query_log</table>
</query_log>
</clickhouse>
EOF
clickhousectl local server configs # List available config files
clickhousectl local server start --config analytics # Start a server with itThe 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.
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).
clickhousectl local install postgres@17
# Start a Postgres instance (defaults: postgres:18, port 5432, user "postgres", db "postgres")
clickhousectl local postgres start
clickhousectl local postgres start --name dev --version 17 --port 5433
clickhousectl local postgres start --user app --database myapp # Generates a random password
clickhousectl local postgres start -e POSTGRES_INITDB_ARGS=--data-checksums
# List everything (ClickHouse + Postgres are merged in `server list`)
clickhousectl local server list
# Connect with psql (uses host psql if installed; otherwise falls back to docker exec)
clickhousectl local postgres client --name dev
clickhousectl local postgres client --name dev --query "SELECT 1"
# Write POSTGRES_HOST/PORT/USER/PASSWORD/DATABASE into .env.local
clickhousectl local postgres dotenv --name dev --local
# Stop / remove. Pass --version when more than one major shares a name.
clickhousectl local postgres stop # Stop "default"
clickhousectl local postgres stop dev
clickhousectl local postgres stop dev --version 17 # disambiguate
clickhousectl local postgres stop-all # Stop all Postgres instances in this project
clickhousectl local postgres remove # Remove "default"
clickhousectl local postgres remove devThe Postgres dotenv command includes the generated password. Do not commit its output; prefer --local when your application reads .env.local.
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, the command exits and asks you to pass --version. Stop preserves the container and metadata so the next start resumes it; only remove tears down the container and deletes the data directory. The unified local server stop-all stops both ClickHouse and Postgres instances in the current project; the dedicated local postgres stop-all remains available when only Postgres should be stopped.
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.
All project-local server data lives inside .clickhouse/ in your project directory. The example below shows ClickHouse entries; Postgres uses the versioned paths described above.
.clickhouse/
├── .gitignore # auto-created, ignores everything
├── credentials.json # cloud API credentials (if configured)
└── servers/
├── default.json # ClickHouse identity and runtime state
├── default/
│ └── data/ # ClickHouse data files for "default" server
├── dev.json # ClickHouse identity and runtime state
└── 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.
Authenticate to ClickHouse Cloud using OAuth (browser-based) or API keys. OAuth provides read-only access. Write operations require an API key; its effective permissions depend on its assigned roles.
If you don't have a ClickHouse Cloud account yet, clickhousectl cloud auth signup opens the sign-up page in your browser.
clickhousectl cloud auth loginThis 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.
# Save credentials locally without putting the secret in shell history
clickhousectl cloud auth login --interactiveauth login --interactive saves credentials 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.
For CI and other automation, inject credentials through your secret manager:
export CLICKHOUSE_CLOUD_API_KEY=your-key
export CLICKHOUSE_CLOUD_API_SECRET=your-secretEnvironment credentials remain in the environment and are not saved by clickhousectl.
For local development, you can instead place them in a .env file, which is read only from the current working directory:
CLICKHOUSE_CLOUD_API_KEY=your-key
CLICKHOUSE_CLOUD_API_SECRET=your-secretDo not commit .env; add it to .gitignore and restrict its file permissions. Credential flags are also available for one-off use, but secrets passed in command arguments may be exposed through shell history or process listings.
Learn how to create API keys.
clickhousectl cloud auth status # Show current auth state (including read-only/read-write labels)
clickhousectl cloud auth logout # Clear all saved credentials (credentials.json & tokens.json)Credential resolution order:
- CLI flags
.clickhouse/credentials.json- Environment variables exported in your session
- Environment variables from
.env - OAuth tokens.
When environment credentials are configured but a credentials file or explicit
CLI flags take precedence, clickhousectl prints a one-line note to stderr.
cloud auth status also marks the environment credentials as configured but
inactive and identifies the source that outranked them.
Pass --debug to a Cloud resource command to print the resolved credential source (and the API URL) to stderr before the command runs. This works with and without --json.
clickhousectl cloud --debug service list
# [debug] auth source: credentials file (.clickhouse/credentials.json)
# [debug] api url: https://api.clickhouse.cloud/v1
# ... normal output ...Manage ClickHouse, Postgres, and other ClickHouse Cloud resources via the API.
clickhousectl cloud org list # List organizations
clickhousectl cloud org get <org-id> # Get organization details
clickhousectl cloud org update <org-id> --name "Renamed Org"
clickhousectl cloud org update <org-id> \
--remove-private-endpoint pe-1,cloud-provider=aws,region=us-east-1 \
--enable-core-dumps false
clickhousectl cloud org prometheus --filtered-metrics true
clickhousectl cloud org usage \
--from-date 2024-01-01 \
--to-date 2024-01-31
# Add --org-id <org-id> to either command when your credentials access multiple organizations.# List services
clickhousectl cloud service list
# Get service details
clickhousectl cloud service get <service-id>
# Create a service with explicit placement and network access
clickhousectl cloud service create --name my-service \
--provider aws \
--region us-east-1 \
--ip-allow <trusted-public-ip>/32
# Create with scaling options
clickhousectl cloud service create --name my-service \
--provider aws \
--region us-east-1 \
--ip-allow <trusted-public-ip>/32 \
--min-replica-memory-gb 8 \
--max-replica-memory-gb 32 \
--num-replicas 2
# Create with specific IP allowlist
clickhousectl cloud service create --name my-service \
--provider aws \
--region us-east-1 \
--ip-allow <trusted-egress-cidr> \
--ip-allow <another-trusted-egress-cidr>
# Create from backup
clickhousectl cloud service create --name restored-service \
--provider aws \
--region us-east-1 \
--ip-allow <trusted-public-ip>/32 \
--backup-id <backup-uuid>
# Create with release channel
clickhousectl cloud service create --name my-service \
--provider aws \
--region us-east-1 \
--ip-allow <trusted-public-ip>/32 \
--release-channel fast
# Create with GA request-only extras
clickhousectl cloud service create --name my-service \
--provider aws \
--region us-east-1 \
--ip-allow <trusted-public-ip>/32 \
--tag env=prod \
--enable-endpoint mysql \
--private-preview-terms-checked \
--enable-core-dumps true
# Start/stop a service
clickhousectl cloud service start <service-id>
clickhousectl cloud service stop <service-id>
# Run SQL over HTTP via the Query API (no local clickhouse binary needed)
clickhousectl cloud service query --name my-service --query "SELECT 1"
clickhousectl cloud service query --id <service-id> --query "SELECT count() FROM system.tables" --format JSONEachRow
clickhousectl cloud service query --name my-service --queries-file schema.sql # "-" reads from stdin
clickhousectl cloud service query --name my-service --database mydb --query "SHOW TABLES"
echo "SELECT 1+1" | clickhousectl cloud service query --name my-service
# Update service metadata and patches
clickhousectl cloud service update <service-id> \
--name my-renamed-service \
--add-ip-allow <trusted-egress-cidr> \
--remove-ip-allow 0.0.0.0/0 \
--add-private-endpoint-id pe-1 \
--release-channel fast \
--enable-endpoint mysql \
--add-tag env=staging \
--transparent-data-encryption-key-id tde-key-1 \
--enable-core-dumps false
# Update replica scaling (vertical autoscaling — fixed replica count, variable memory)
clickhousectl cloud service scale <service-id> \
--min-replica-memory-gb 24 \
--max-replica-memory-gb 48 \
--num-replicas 3 \
--idle-scaling true \
--idle-timeout-minutes 10
# Horizontal autoscaling — fixed memory per replica, variable replica count
# (requires the horizontal autoscaling org feature)
clickhousectl cloud service create --name my-service \
--provider aws --region us-east-1 --ip-allow <trusted-public-ip>/32 \
--min-replica-memory-gb 24 --max-replica-memory-gb 24 \
--min-replicas 2 --max-replicas 8 --autoscaling-mode horizontal
clickhousectl cloud service scale <service-id> \
--min-replica-memory-gb 24 --max-replica-memory-gb 24 \
--min-replicas 2 --max-replicas 8 --autoscaling-mode horizontal
# Reset password with generated credentials
clickhousectl cloud service reset-password <service-id>
# Reset password with precomputed hashes
clickhousectl cloud service reset-password <service-id> \
--new-password-hash <base64-sha256-hash> \
--new-double-sha1-hash <mysql-double-sha1-hash>
# Query endpoint management (manual, for sharing keys with other tools)
clickhousectl cloud service query-endpoint get <service-id>
clickhousectl cloud service query-endpoint create <service-id> \
--role sql_console_read_only \
--open-api-key <api-key-id> \
--allowed-origins https://app.example.com
clickhousectl cloud service query-endpoint delete <service-id>
# Private endpoint management
clickhousectl cloud service private-endpoint create <service-id> --endpoint-id vpce-123
clickhousectl cloud service private-endpoint get-config <service-id>
# Backup configuration
clickhousectl cloud service backup-config get <service-id>
clickhousectl cloud service backup-config update <service-id> \
--backup-period-hours 24 \
--backup-retention-period-hours 720 \
--backup-start-time 02:00
# Service Prometheus configuration
clickhousectl cloud service prometheus <service-id> --filtered-metrics true
# Delete a service (must be stopped first)
clickhousectl cloud service delete <service-id>
# Force delete: stops a running service then deletes
clickhousectl cloud service delete <service-id> --forceUse clickhousectl cloud service create --help for the complete option list. If omitted, --provider defaults to aws, --region defaults to us-east-1, and the IP allowlist defaults to 0.0.0.0/0; production workflows should normally set all three explicitly. When the create response includes an initial password, it is shown only once.
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): when no per-service key is stored,
cloud service queryfirst uses the authenticated API key directly. This supports services whose Query API endpoint already authorizes that key without requiring permission to create another key. If the key or endpoint is not authorized, the CLI provisions a dedicated API key and binds it to the service. Those generated query credentials, the endpoint ID, exact management API key ID, and provisioning organization ID are stored in.clickhouse/credentials.jsonunderservice_query_keys.<service-id>, alongside any user-level API key. Subsequent queries use that key. The generated key 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. After deleting a service, cloud service delete deletes an auto-provisioned key by its stored management and organization IDs, then removes the local record. Legacy records without that metadata remain readable, but service deletion will not guess at a cloud key by name; a partial record with a management ID is retained for manual recovery.
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.
Manage ClickHouse Cloud managed Postgres services. All write commands require API key auth.
# List / get
clickhousectl cloud postgres list
clickhousectl cloud postgres list --filter state=running
clickhousectl cloud postgres get <pg-id>
# Create
clickhousectl cloud postgres create \
--name my-pg \
--provider aws \
--region us-east-1 \
--size c6gd.xlarge \
--pg-version 18
# Create with HA + tags + advanced config
clickhousectl cloud postgres create \
--name my-pg \
--provider aws \
--region us-east-1 \
--size c6gd.xlarge \
--pg-version 18 \
--ha-type sync \
--tag env=prod \
--pg-config-file ./pg.json
# Update size, HA, or tags (all flags optional)
clickhousectl cloud postgres update <pg-id> \
--size m7i.4xlarge \
--add-tag env=prod --remove-tag legacy
# Delete
clickhousectl cloud postgres delete <pg-id>
# CA certificates
clickhousectl cloud postgres certs get <pg-id> # raw PEM to stdout
clickhousectl cloud postgres certs get <pg-id> --output ca.pem # file (mode 0600 on unix)
# Runtime configuration
clickhousectl cloud postgres config get <pg-id>
clickhousectl cloud postgres config patch <pg-id> --set max_connections=500 --set random_page_cost=1.1
clickhousectl cloud postgres config patch <pg-id> --file patch.json
# Replace the entire configuration only with a complete object obtained from `config get`
clickhousectl cloud postgres config replace <pg-id> --file complete-config.json
# Password
clickhousectl cloud postgres reset-password <pg-id> --generate
# Read replica and PITR restore
clickhousectl cloud postgres read-replica create <pg-id> --name replica-1
clickhousectl cloud postgres restore <pg-id> \
--name restored \
--restore-target <recent-RFC3339-time-within-retention>
# Lifecycle
clickhousectl cloud postgres restart <pg-id>
clickhousectl cloud postgres promote <pg-id>
clickhousectl cloud postgres switchover <pg-id>Use clickhousectl cloud postgres create --help for the complete option list. Save any initial password and connection string in the create response because later postgres get responses do not return credentials. If both are omitted, run clickhousectl cloud postgres reset-password <postgres-id> --generate.
clickhousectl cloud backup list <service-id>
clickhousectl cloud backup get <service-id> <backup-id>Manage ClickPipes for ingesting data into ClickHouse Cloud from external sources.
# List ClickPipes for a service
clickhousectl cloud clickpipe list <service-id>
# Get ClickPipe details
clickhousectl cloud clickpipe get <service-id> <clickpipe-id>
# Start/stop/resync a ClickPipe
clickhousectl cloud clickpipe start <service-id> <clickpipe-id>
clickhousectl cloud clickpipe stop <service-id> <clickpipe-id>
clickhousectl cloud clickpipe resync <service-id> <clickpipe-id> # CDC pipes only
# Delete a ClickPipe
clickhousectl cloud clickpipe delete <service-id> <clickpipe-id>
# Update scaling
clickhousectl cloud clickpipe scale <service-id> <clickpipe-id> \
--replicas 2 --cpu-millicores 250 --memory-gb 1
# Get/update settings
clickhousectl cloud clickpipe settings get <service-id> <clickpipe-id>
clickhousectl cloud clickpipe settings update <service-id> <clickpipe-id> \
--streaming-max-insert-wait-ms 10000Each source type has its own subcommand under clickpipe create:
The current source commands accept credentials as command-line options. Load values from your secret manager into environment variables, run them only in a trusted environment, and do not commit source credentials to scripts; expanded values may still be visible in process listings while a command runs.
# From S3 / object storage (one-shot snapshot)
clickhousectl cloud clickpipe create object-storage <service-id> \
--name my-s3-pipe \
--source-url 'https://bucket.s3.us-east-1.amazonaws.com/data/**' \
--format JSONEachRow \
--database default --table events \
--column "event_id:Int64" --column "name:String"
# 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)
clickhousectl cloud clickpipe create object-storage <service-id> \
--name my-s3-continuous-pipe \
--source-url 'https://bucket.s3.us-east-1.amazonaws.com/data/**' \
--format JSONEachRow \
--continuous \
--queue-url 'https://sqs.us-east-1.amazonaws.com/123/my-queue' \
--start-after obj-key-001 \
--database default --table events \
--column "event_id:Int64" --column "name:String"
# From Google Cloud Storage (object storage)
clickhousectl cloud clickpipe create object-storage <service-id> \
--name my-gcs-pipe \
--storage-type gcs \
--source-url 'https://storage.googleapis.com/bucket/data/**' \
--format JSONEachRow \
--service-account-file ./sa-key.json \
--database default --table events \
--column "event_id:Int64" --column "name:String"
# From Kafka / Redpanda / Confluent / MSK
clickhousectl cloud clickpipe create kafka <service-id> \
--name my-kafka-pipe \
--brokers 'broker:9092' --topics events \
--format JSONEachRow \
--kafka-type redpanda \
--auth SCRAM-SHA-256 \
--username "$KAFKA_USERNAME" --password "$KAFKA_PASSWORD" \
--ca-certificate ./ca.crt \
--database default --table events \
--column "event_id:Int64" --column "name:String"
# From Amazon Kinesis
clickhousectl cloud clickpipe create kinesis <service-id> \
--name my-kinesis-pipe \
--stream-name events --region us-east-1 \
--format JSONEachRow \
--auth IAM_ROLE --iam-role "$KINESIS_IAM_ROLE_ARN" \
--database default --table events \
--column "event_id:Int64" --column "name:String"
# From PostgreSQL (CDC)
clickhousectl cloud clickpipe create postgres <service-id> \
--name my-pg-pipe \
--host db.example.com --pg-database mydb \
--username "$POSTGRES_USERNAME" --password "$POSTGRES_PASSWORD" \
--table-mapping "public.users:public_users" \
--table-mapping "public.orders:public_orders"
# 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)
clickhousectl cloud clickpipe create mysql <service-id> \
--name my-mysql-pipe \
--host mysql.example.com \
--username "$MYSQL_USERNAME" --password "$MYSQL_PASSWORD" \
--table-mapping "mydb.users:mydb_users" \
--server-id 4242
# From MongoDB (CDC)
clickhousectl cloud clickpipe create mongodb <service-id> \
--name my-mongo-pipe \
--uri 'mongodb+srv://cluster.example.net/mydb' \
--username "$MONGODB_USERNAME" --password "$MONGODB_PASSWORD" \
--table-mapping "mydb.users:mydb_users"
# From BigQuery (snapshot)
clickhousectl cloud clickpipe create bigquery <service-id> \
--name my-bq-pipe \
--service-account-file ./sa-key.json \
--staging-path gs://bucket/staging \
--table-mapping "dataset.table:target_table"Use clickhousectl cloud clickpipe create <source> --help for the full list of options per source type.
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). Schema discovery requires API-key authentication:
# Discover schema from Kafka
clickhousectl cloud clickpipe schema-discover <service-id> kafka \
--brokers 'broker:9092' --topics events \
--format JSONEachRow \
--auth SCRAM-SHA-256 \
--username "$KAFKA_USERNAME" --password "$KAFKA_PASSWORD"
# Discover schema from Kinesis
clickhousectl cloud clickpipe schema-discover <service-id> kinesis \
--stream-name events --region us-east-1 \
--format JSONEachRow \
--auth IAM_ROLE --iam-role "$KINESIS_IAM_ROLE_ARN"Add --json (or run as a coding agent) for machine-readable output.
Role IDs used by member, invitation, and API-key commands currently come from the ClickHouse Cloud Console or API.
clickhousectl cloud member list
clickhousectl cloud member get <user-id>
clickhousectl cloud member update <user-id> --role-id <role-id>
clickhousectl cloud member remove <user-id>clickhousectl cloud invitation list
clickhousectl cloud invitation create --email dev@example.com --role-id <role-id>
clickhousectl cloud invitation get <invitation-id>
clickhousectl cloud invitation delete <invitation-id>clickhousectl cloud key list
clickhousectl cloud key get <key-id>
clickhousectl cloud key create --name ci-key \
--role-id <role-id> \
--expires-at <future-RFC3339-time> \
--ip-allow <trusted-egress-ip>/32
clickhousectl cloud key update <key-id> \
--name renamed-key \
--state disabled
clickhousectl cloud key delete <key-id>clickhousectl cloud activity list --from-date 2024-01-01 --to-date 2024-12-31
clickhousectl cloud activity get <activity-id>Use the --json flag for machine-readable output on commands that return structured data.
clickhousectl cloud --json service list
clickhousectl cloud --json service get <service-id>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. Protocol-oriented commands retain their natural output: Prometheus commands emit text, cloud service query uses a ClickHouse format such as JSONEachRow, and Postgres runtime configuration is JSON already.
Usage errors and cancelled actions use distinct exit codes.
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Error (anything not classified below) |
2 |
Usage error (invalid command line) |
3 |
Cancelled (user aborted) |
4 |
Auth required (no credentials, 401/403, OAuth-only writes) |
Install the official ClickHouse Agent Skills from ClickHouse/agent-skills.
# Default: interactive mode for humans, choose scope, then choose agents
clickhousectl skills
# Non-interactive: install into every supported project-local agent folder
clickhousectl skills --all
# Non-interactive: install only into detected agents
clickhousectl skills --detected-only
# Non-interactive: install into every supported global agent folder
clickhousectl skills --global --all
# Non-interactive: install only into detected global agents
clickhousectl skills --global --detected-only
# Non-interactive: install into specific project-local agents
clickhousectl skills --agent claude --agent codex
# Non-interactive: install into specific global agents
clickhousectl skills --global --agent claude --agent codexThe 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.
--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
clickhousectl can update itself to the latest release:
# Update to the latest version
clickhousectl update
# Check for updates without installing
clickhousectl update --checkThe 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.
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 server 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 sent before you have seen the notice unless you explicitly enable telemetry with clickhousectl telemetry enable. The first run normally 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. Explicitly enabling telemetry starts it immediately 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
clickhousectl telemetry disable
# Per environment/shell (https://consoledonottrack.com)
export DO_NOT_TRACK=1To 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 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:
export CLICKHOUSE_CLOUD_API_KEY=...
export CLICKHOUSE_CLOUD_API_SECRET=...
export CLICKHOUSE_CLOUD_TEST_ORG_ID=...
export CLICKHOUSE_CLOUD_TEST_PROVIDER=aws
export CLICKHOUSE_CLOUD_TEST_REGION=eu-west-1
# Required for the org integration suite (members + invitations need a
# second user in the test org); optional otherwise.
export CLICKHOUSE_CLOUD_TEST_SECONDARY_USER_ID=...Run a suite:
cargo test -p clickhouse-cloud-api --test integration_test -- --ignored --nocapture
cargo test -p clickhouse-cloud-api --test integration_postgres_test -- --ignored --nocapture
cargo test -p clickhouse-cloud-api --test integration_org_test -- --ignored --nocaptureBy 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:
export CONTINUE_ON_NON_BLOCKING_FAILURES=1- macOS (aarch64, x86_64) or Linux (aarch64, x86_64)
- Cloud read operations support OAuth; writes and some operations such as ClickPipe schema discovery require a ClickHouse Cloud API key