Store and track Clickhouse SQL files in Git, apply them reproducibly, and document changes alongside schema migrations.
Keeping every analytical query in Git guarantees auditability, easy rollback, and teamwork—exactly like code. Developers can peer-review SQL, link it to tickets, and run CI checks before deploying.
Create one .sql
file per business object: customers.sql
, daily_revenue.sql
, etc. Include CREATE VIEW
or CREATE TABLE AS
statements plus comments describing intent, owner, and last update.
Use a clickhouse/
folder with sub-directories like analytics/
, dashboards/
, and migrations/
.CI pipelines can apply only changed files inside migrations/
to production.
Pair Git commits with a CI job—GitHub Actions or GitLab CI—that calls clickhouse-client -n -q "$(cat file.sql)"
. Tag releases so you can redeploy any historical state.
Add ERB- or Jinja-style placeholders ({{database}}
) in SQL files.During CI, render them from secrets, then pipe to clickhouse-client
.
Place queries like:
CREATE OR REPLACE VIEW v_customer_ltv AS
SELECT c.id,
sum(oi.quantity * p.price) AS lifetime_value
FROM Customers c
JOIN Orders o ON o.customer_id = c.id
JOIN OrderItems oi ON oi.order_id = o.id
JOIN Products p ON p.id = oi.product_id
GROUP BY c.id;
Commit and push; reviewers can comment just like on application code.
Feature branches for each metric, pull requests for review, squashed merge into main
.Tag database releases (v1.4-schema
) and deploy via CI.
Keep DDL in migrations/
with incremental numbering (e.g., 20240508_01_add_column.sql
). CI runs them sequentially; analytical queries in views/
get redeployed afterwards.
SETTINGS allow_experimental_lightweight_delete = 1
in test env to avoid production accidents.sqlfluff
or pgFormatter
in CI.clickhouse-test
or snapshot testing tools..
Yes. Store CREATE MATERIALIZED VIEW
statements in Git and include POPULATE
logic. Ensure CI grants needed privileges.
Never hardcode. Use placeholders and inject via CI environment variables.
CI should stop the pipeline and alert. Fix the SQL, push a new commit, and rerun.