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-formatis the source of truth. Runclang-format -iover 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/.cpppair when reasonable.pragma onceover include guards. Avoid leakingusing namespaceinto 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 insrc/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
Exceptionto swallow it. If you must, log and re-throw or return a specific status. - New error codes go at the bottom of
ErrorCodes.cppto 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, notf(), when you mean the function itself rather than its application. - Say "exception" instead of "crash" for logical errors.
- Say
ASan, notASAN(and similar forMSan,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(seesrc/Common/BackgroundSchedulePool.cpp). Don't spawnstd::threads ad hoc. - Never use
sleepto fix a race condition. This is called out inAGENTS.mdin unusually strong terms ("this is stupid and not acceptable"). If you find yourself reaching forsleep, you have not understood the synchronization. Use proper waits, condition variables, futures, or Keeper watches. - Use
Stopwatch(src/Common/Stopwatch.h) for timings, not rawgettimeofday.
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 thannew/delete. - For per-query temporaries that may spill to disk, use
TemporaryDataOnDisk.
Logging
- Use the
logmacros insrc/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,tablewhere relevant. - Avoid
std::cout/std::cerroutsideprograms/initialization paths.
Settings
- Add a setting via the X-macros in
src/Core/Settings.cpp(orServerSettings.cpp,MergeTreeSettings.cpp). The macro generates the typed accessor, thesystem.settingsrow, 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
StorageFactoryfrom aregisterStorageX()function. - New functions register in
FunctionFactory. - New aggregate functions register in
AggregateFunctionFactory. - New table functions register in
TableFunctionFactory.
Performance hygiene
- Use
Block/Columnoperations rather than per-row loops. The vectorized path is what makes ClickHouse fast. - Prefer
IColumn::insertRange*over per-rowinsertfor 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-parallelor otherno-*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
-jornproctoninja. 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.mdas 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.