Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ clickhousectl local server start --name dev # Named "dev"
clickhousectl local server start --version stable # 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 --http-port 8124 --tcp-port 9001 # Explicit ports
clickhousectl local server start -- --config-file=/path/to/config.xml
clickhousectl local server start --config-file analytics # Apply a custom config (see "Custom config files" below)

# List custom config files available to --config-file
clickhousectl local server configs

# List all servers (running and stopped)
clickhousectl local server list
Expand Down Expand Up @@ -186,6 +189,28 @@ clickhousectl local server dotenv --user default --password secret --database my

**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:

```bash
mkdir -p ~/.clickhouse/configs
cat > ~/.clickhouse/configs/analytics.xml <<'EOF'
<clickhouse>
<query_log>
<database>system</database>
<table>query_log</table>
</query_log>
</clickhouse>
EOF
# List available config files
clickhousectl local server start --config-file analytics # Start a server with it
```

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-file analytics` or `--config-file analytics.xml`). `--config-file` takes a name within `~/.clickhouse/configs/` **not a path**.

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-file` 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.
Expand Down
6 changes: 6 additions & 0 deletions crates/clickhousectl/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ pub enum Error {
#[error("Invalid server name '{0}': must not contain path separators or '..'")]
InvalidServerName(String),

#[error("{0}")]
ConfigNotFound(String),

#[error("Invalid config name '{0}': must be a file in the configs dir, not a path (no '/', '\\', or '..')")]
InvalidConfigName(String),

#[error("Docker is not available: {0}")]
DockerNotAvailable(String),

Expand Down
71 changes: 71 additions & 0 deletions crates/clickhousectl/src/local/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ CONTEXT FOR AGENTS:
Runs in background by default. Use --foreground (-F / --fg) to run in foreground.
If --name is given and that server is already running, the command will error.
Shows count of already-running servers before starting.
Use --config-file <NAME> to apply a custom ClickHouse config file from ~/.clickhouse/configs/
(see `clickhousectl local server configs`). The file is merged as an overlay on top of
ClickHouse's built-in defaults (via config.d), so it can contain just the settings you want
to change (e.g. <query_log>). The data directory and ports stay managed regardless of the
file's contents (they are forced as command-line overrides).
Related: `clickhousectl local server list` to see servers, `clickhousectl local server stop <name>` to stop one.")]
Start {
/// Server name (default: \"default\", or random if default is already running)
Expand All @@ -187,11 +192,27 @@ CONTEXT FOR AGENTS:
#[arg(long, alias = "fg", short = 'F')]
foreground: bool,

/// Overlay a named config file from ~/.clickhouse/configs/ on top of the defaults (see `server configs`)
#[arg(long, value_name = "NAME")]
config_file: Option<String>,

/// Arguments to pass to clickhouse-server
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},

/// List custom config files available to `server start --config-file`
#[command(after_help = "\
CONTEXT FOR AGENTS:
Lists ClickHouse config files in ~/.clickhouse/configs/ and prints that directory's path.
Drop a config file there (e.g. analytics.xml) and start a server with it via
`clickhousectl local server start --config-file analytics`. The file is overlaid on top of
ClickHouse's built-in defaults (config.d merge), so it only needs the settings you want to
change. Files may be .xml, .yaml, or .yml; reference them by name with or without the
extension.
Related: `clickhousectl local server start --config-file <NAME>`.")]
Configs,

/// List all server instances (running and stopped)
#[command(after_help = "\
CONTEXT FOR AGENTS:
Expand Down Expand Up @@ -411,3 +432,53 @@ CONTEXT FOR AGENTS:
local: bool,
},
}

#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{Cli, Commands};
use clap::Parser;

fn local_command(args: &[&str]) -> LocalCommands {
let mut argv = vec!["clickhousectl", "local"];
argv.extend_from_slice(args);
let cli = Cli::try_parse_from(argv).unwrap();
let Commands::Local(local) = cli.command else {
panic!("expected local command");
};
local.command
}

#[test]
fn parses_server_start_config_file() {
let LocalCommands::Server {
command: ServerCommands::Start { config_file, .. },
} = local_command(&["server", "start", "--config-file", "analytics"])
else {
panic!("expected server start");
};
assert_eq!(config_file.as_deref(), Some("analytics"));
}

#[test]
fn server_start_config_file_defaults_to_none() {
let LocalCommands::Server {
command: ServerCommands::Start { config_file, args, .. },
} = local_command(&["server", "start"])
else {
panic!("expected server start");
};
assert_eq!(config_file, None);
assert!(args.is_empty());
}

#[test]
fn parses_server_configs() {
let LocalCommands::Server {
command: ServerCommands::Configs,
} = local_command(&["server", "configs"])
else {
panic!("expected server configs");
};
}
}
Loading