Open-Source Wikis

/

ClickHouse

/

How to contribute

/

Patterns and conventions

clickhouse/clickhouse

Patterns and conventions

ClickHouse is a large, opinionated codebase. The conventions on this page are enforced by CI or by reviewers; reading them up front saves a round trip.

The authoritative sources are AGENTS.md, the docs under docs/en/development/, and .clang-format / .clang-tidy. This page summarizes the most-cited rules.

C++ style

  • Allman braces. Opening brace on a new line, always. CI rejects K&R style.
  • clang-format. The repo's .clang-format is the source of truth. Run clang-format -i over every file you touch.
  • clang-tidy. Configured in .clang-tidy. Some checks are warnings-as-errors.
  • C++23. The codebase targets C++23 with clang. GCC is not supported.
  • Headers. One class per .h/.cpp pair when reasonable. pragma once over include guards. Avoid leaking using namespace into headers.

Naming

Construct Convention
Classes / types PascalCase
Functions / methods camelCase
Variables snake_case
Members snake_case (some legacy m_ / trailing _ exists; don't add new ones)
Constants SCREAMING_SNAKE_CASE
Enums PascalCase enum, PascalCase enumerators
Files Match the primary class name, e.g. MergeTreeData.cpp

The DB code historically uses namespace DB { ... } for everything user-facing.

Error handling

  • Use throw Exception(error_code, "...", args...); (src/Common/Exception.h). Error codes are X-macroed in src/Common/ErrorCodes.cpp.
  • Per AGENTS.md, refer to logical errors as exceptions, not crashes — release builds throw rather than abort.
  • Avoid std::terminate-style aborts. The release build is required to recover.
  • Do not catch Exception to swallow it. If you must, log and re-throw or return a specific status.
  • New error codes go at the bottom of ErrorCodes.cpp to keep wire compatibility.

Comments and code references

Per AGENTS.md:

  • Wrap literal SQL keywords, class names, function names, and excerpts from log messages in inline backticks: `MergeTree`, `clickhouse-keeper`.
  • Refer to a function as f, not f(), when you mean the function itself rather than its application.
  • Say "exception" instead of "crash" for logical errors.
  • Say ASan, not ASAN (and similar for MSan, TSan, UBSan).
  • Documentation under docs/ requires explicit anchors {#kebab-case-anchor} on every heading and a frontmatter block at the top of new files.

Threading

  • Long-lived background work goes on a dedicated BackgroundSchedulePool (see src/Common/BackgroundSchedulePool.cpp). Don't spawn std::threads ad hoc.
  • Never use sleep to fix a race condition. This is called out in AGENTS.md in unusually strong terms ("this is stupid and not acceptable"). If you find yourself reaching for sleep, you have not understood the synchronization. Use proper waits, condition variables, futures, or Keeper watches.
  • Use Stopwatch (src/Common/Stopwatch.h) for timings, not raw gettimeofday.

Memory

  • MemoryTracker (src/Common/MemoryTracker.cpp) accounts every allocation. Bypassing it is rare and intentional (e.g. signal handler code).
  • Allocators are layered: Arena, MemoryChunk, PODArray, HashTable<...>::Allocator. Reach for the right one rather than new/delete.
  • For per-query temporaries that may spill to disk, use TemporaryDataOnDisk.

Logging

  • Use the log macros in src/Common/Logger.h: LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR. They are no-ops below the configured level.
  • Make log messages structured-friendly: include query_id, database, table where relevant.
  • Avoid std::cout / std::cerr outside programs/ initialization paths.

Settings

  • Add a setting via the X-macros in src/Core/Settings.cpp (or ServerSettings.cpp, MergeTreeSettings.cpp). The macro generates the typed accessor, the system.settings row, and the docs string.
  • Setting names are snake_case. Defaults must be backward-compatible.
  • Document the setting both in the inline help string and in docs/en/operations/settings/.

SQL changes

  • New SQL keywords go through the parser in src/Parsers/. Add tokens to the lexer (Lexer.cpp) and the parser combinator that needs them.
  • New table engines register themselves in StorageFactory from a registerStorageX() function.
  • New functions register in FunctionFactory.
  • New aggregate functions register in AggregateFunctionFactory.
  • New table functions register in TableFunctionFactory.

Performance hygiene

  • Use Block/Column operations rather than per-row loops. The vectorized path is what makes ClickHouse fast.
  • Prefer IColumn::insertRange* over per-row insert for bulk operations.
  • For hot inner loops, check the assembly (utils/c++expr -b ... or .claude/tools/analyze-assembly.py).
  • ARM machines in CI are not slow — assume parity with x86 for performance tests (AGENTS.md).

Testing patterns

  • Stateless first. Reserve integration tests for things that genuinely need a multi-node setup.
  • Don't add no-parallel or other no-* tags unless strictly necessary.
  • Prefer adding a new test file to extending an existing one. The numbering convention groups related tests.

Build

  • Don't pass -j or nproc to ninja. It picks an appropriate parallelism on its own (AGENTS.md).
  • Always redirect ninja output to a build log under the build directory and analyze the log with a subagent (AGENTS.md).

Documentation

  • Headings under docs/ need {#kebab-anchor} markers.
  • New doc files need the frontmatter (see docs/en/development/continuous-integration.md as a model).
  • The wiki under droid-wiki/ (this folder) is generated/updated by automation; manual edits are usually overwritten.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – ClickHouse wiki | Factory