Declarative SQL streaming pipelines for ClickHouse, with replay-aware builds and staged deployments.
SQLTide lets data teams define continuously updating ClickHouse pipelines in typed SQL, inspect the affected graph before making changes, and rebuild it from retained streaming history when logic changes.
It brings dbt-style authoring and deployment workflows to streaming workloads:
- Declarative models compile into ClickHouse tables and materialized views.
- Replay-aware builds reconstruct affected models from retained stream history.
- Safe planning shows the graph and warehouse operations before execution.
- Staged deployments support review, audit, promotion, and graph-level rollback.
- Built-in observability covers sources, lag, lineage, runs, quality checks, and sensors.
SQLTide currently targets ClickHouse and supports managed Kafka landing or adopted external stream tables.
Install
Requires Python 3.12 or newer.
pip install sqltide
sqt --help
Upgrading from StreamBuild
SQLTide is the new name for StreamBuild. Install sqltide in place of streambuild; the CLI is now
sqt. Names you author or configure change without a compatibility layer:
- Rename
streambuild_project.tomlandstreambuild_local.tomltosqltide_project.tomlandsqltide_local.toml, andSTREAMBUILD_*environment variables toSQLTIDE_*. - Import
sqltideinstead ofstreambuildin macros, sensors, and providers. - Trusted proxies send
X-SQLTide-Userby default, and browser sessions sign in again. - Ignore
.sqltide/instead of.streambuild/in your project's.gitignore.
State that SQLTide stores carries over automatically. The first sqt command against a target renames
its _streambuild_* metadata tables to _sqltide_*, and refuses while a StreamBuild run still holds
the target lock. Accounts in .streambuild/ or a shared control-store database are renamed the same
way. Managed Kafka sources keep their existing consumer groups, so ingestion resumes from committed
offsets. Upgrade every machine and CI job that writes to a target together: StreamBuild cannot read a
renamed target.
Quickstart
The included deterministic commerce demo runs locally with Redpanda and ClickHouse. It requires
Docker with Compose, Node.js 20.19 or newer, npm, and uv:
git clone https://github.com/sqlstack-io/sqltide.git
cd sqltide
make ui-install ui-build
uv tool install --editable .
cd examples/orders_demo
cp .env.example .env
make start
make dev
Open http://127.0.0.1:8000 to inspect three Kafka partitions, retained messages, replay-safe model
facts, tests, audits, and Kafka lag. See the commerce events demo
for its fixed event contract and controlled warning/recovery walkthrough.
How it works
Kafka or an adopted stream table
|
v
retained landing data
|
v
typed SQL models -> ClickHouse tables and materialized views
|
v
plan -> build or stage -> audit -> promote
SQLTide follows __source() and __ref() dependencies to compile the model graph. Live
materialized views keep it current; retained replay columns let a later build reconstruct the
affected scope after SQL changes.
Project
sqltide_project.toml
sources/
orders.yml
macros/
common.py
pipelines/
pl__orders/
pipeline.toml
order_totals.sql
audits/
tests/
Minimal configuration:
name = "orders"
default_target = "dev"
[connection]
host = "localhost"
port = 8123
username = "default"
password = "${ENV:CLICKHOUSE_PASSWORD}"
[defaults]
pipeline_mode = "direct"
[defaults.sources.kafka.retention]
duration = "7d"
timestamp = "broker"
fallback = "landed"
cap_at = "landed"
[defaults.models.retention]
duration = "7d"
timestamp_column = "kafka_timestamp"
cap_at_column = "ingested_at"
when_missing = "error"
[ui]
timezone = "Europe/London"
[dependencies]
model_reference_scope = "pipeline"
[[dependencies.allowed_cross_pipeline_references]]
upstream_pipeline = "pl__shared_dimensions"
downstream_pipeline = "pl__orders"
[targets.dev]
database = "analytics"
Developer-specific target and connection overrides belong in the gitignored
sqltide_local.toml.
Sources
Managed Kafka source:
sources:
- name: orders
kind: kafka
broker_list: kafka:9092
topic: source.orders
replay_boundary:
mode: offsets
SQLTide owns managed Kafka landing objects. It validates but never mutates adopted source tables. See the pipeline documentation for adopted stream-table configuration.
Typed retention defaults are checked against each compiled schema. A pipeline can override the
model default in pipeline.toml with [defaults.models.retention]; an individual table model can
override it with retention (...) or opt out with retention false. Specific models and sources
can continue to use free-form ttl expressions when adapter-specific behavior is required.
Pipelines
Each direct child of pipelines/ is a pipeline. Its directory name is its logical name:
pipelines/
pl__orders/
staging/
orders_clean.sql
order_totals.sql
Nested directories organize models but do not change pipeline identity. Pipeline, source, and model names share one namespace and must be unique.
Projects default to dependencies.model_reference_scope = "project", which permits model
references across pipeline directories for compatibility. Set the committed policy to "pipeline"
to keep model dependencies within their owning pipeline. Managed and adopted sources remain
shareable across pipelines under either policy.
Pipeline scope can grant narrow directional exceptions with
dependencies.allowed_cross_pipeline_references. Each entry permits models in
downstream_pipeline to reference models in upstream_pipeline; reverse access requires a
separate entry. Both pipelines must exist. These exceptions do not permit references between
direct and virtual pipelines.
Models
MODEL (
engine "MergeTree()",
order_by ["order_id", "_replay_partition", "_replay_offset"],
);
SELECT
order_id::String AS order_id,
_replay_partition::Int32 AS _replay_partition,
_replay_offset::Int64 AS _replay_offset,
_replay_timestamp::DateTime64(3) AS _replay_timestamp
FROM __source("orders")
Models must project explicit output types. Table models preserve replay lineage through normalized
_replay_* columns. Terminal query views use MODEL (kind view).
Python functions under macros/ are available in model, test, and audit SQL as @function_name().
Workflow
sqt discover # inspect authored resources
sqt compile # offline validation and artifacts
sqt plan # read-only warehouse plan
sqt build # confirm and execute
sqt test
sqt audit
sqt dev # local UI at 127.0.0.1:8000
Select a model or pipeline with repeatable selectors:
sqt plan --select pipeline:pl__orders
sqt build --select order_totals --start-time 2026-08-01T00:00:00Z
sqt compile is offline. sqt plan reads warehouse state but cannot mutate it. sqt build replans
immediately before execution so an approved command never relies on a stale plan.
Build modes
| Mode | Behavior | Best for |
|---|---|---|
| Direct | Rebuilds selected live relations immediately | Development and explicitly controlled live changes |
| Virtual | Builds deployment-specific relations before promotion | Review, validation, and production releases |
| Mixed | Stages virtual pipelines before applying direct pipelines | Projects containing both deployment strategies |
Deployments
Set pipeline_mode = "virtual" project-wide or mode = "virtual" in pipeline.toml.
sqt build
sqt deployment list
sqt deployment show <deployment-id>
sqt deployment diff <deployment-id>
sqt deployment audit <deployment-id>
sqt deployment promote <deployment-id>
sqt deployment rollback --previous
Promotion and rollback switch stable views one relation at a time. Rollback restores a retained publication's bindings, not a historical data snapshot.
Destructive Operations
SQLTide can destroy selected deployed pipelines while retaining their authored definitions,
managed sources, and replay data. A target reset additionally removes managed source and replay
relations, but preserves every _sqltide_* metadata table, account and authorization state,
Kafka offsets, and the reset's own run evidence.
sqt destroy --target uat --select pipeline:pl__orders pipeline:pl__reporting
sqt reset-target --target uat
Both commands require an interactive terminal. They print a frozen impact plan, require a separate review decision, and then prompt for exact pipeline-name challenges from that plan. There is no non-interactive approval option or administrator bypass. Execution locks the target, replans, and rejects manifest or warehouse drift before the first drop. Unselected downstream pipelines block a plan rather than being silently included. Standalone CLI execution also requires the local OS user to be an active built-in administrator in the SQLTide control store.
UI plans and their review state are durable, actor-bound, and atomically single-use across server restarts and workers. Standalone CLI plans use the same durable control-store representation.
Classify production targets in committed project configuration so reset requires the additional
exact PRODUCTION challenge even when the target has a non-standard name:
[targets.live]
production = true
[targets.live.destruction]
max_table_size_to_drop = "100GiB"
max_table_size_to_drop is an optional committed, target-scoped ClickHouse safety ceiling for
each relation, not the aggregate plan size. It must be a finite positive byte-size string and cannot
be overridden from sqltide_local.toml. SQLTide applies it only to that target's reviewed
destruction DROP statements, freezes the override and server default into each plan,
and still relies on ClickHouse to enforce the ceiling when every DROP executes. Other SQLTide
queries continue to use the target connection and server defaults.
Ownership generations, external dependants in every ClickHouse database, and target/database drift are checked before execution. Historical deployment metadata alone never authorizes deletion of a live same-name relation. Target mutation locks remain fail-closed after a crashed owner; SQLTide does not use an age-based automatic takeover that could overlap a long-running ClickHouse query.
The Pipelines UI exposes the same planner and executor through multi-selection and the dedicated
pipeline.destroy and target.reset permissions. Every generated statement, actor, challenge,
result, and observed remaining object after a partial failure is retained in Runs. A failed residual
catalog read is recorded as unavailable rather than as an empty target. Failed destructive Runs can
create a fresh recovery plan from their recorded root selection; old SQL and historical derived
closure are never replayed.
Development UI
sqt dev serves a warehouse-backed interface for one resolved project and target. It provides:
- overview, lineage, pipeline, catalog, source, topic, and message inspection
- connected plan previews and protected-pipeline confirmation
- direct, virtual, and mixed build execution
- deployment inventory, diff, promotion, and cleanup
- frozen bulk pipeline destruction and target reset plans with typed confirmation
- durable run timelines, statement progress, cancellation, and stale-run recovery guidance
- quality history, scheduler health, sensors, and dead-letter recovery
Run observability is warehouse-backed. A silent run becomes unresponsive after 45 seconds and
presumed_failed after [defaults].run_presumed_failed_after (default 10m). A new build is blocked
until that safety window expires to prevent overlapping warehouse writes.
Shared installations support trusted-proxy or password authentication with project-scoped roles. See the documentation for access control and operational configuration.
Guarantees
sqt compileis connection-free and writes disposable artifacts undertarget/.sqt planis read-only;sqt buildalways replans against current warehouse state.- Lifecycle state is append-only metadata in the selected target database.
- Failed or cancelled builds are rerun, never resumed from copied SQL artifacts.
- Workflow statements execute serially to avoid unbounded ClickHouse memory pressure.
Documentation
Development
Install the locked Python and UI dependencies before running the verification lanes:
uv sync --locked --all-groups
make ui-install ui-build
make check-ci
make ui-verify
make test
Run every verification lane with:
make test-all
The integration and browser lanes provision real ClickHouse and Redpanda containers, so Docker must be running. Install Chromium and its system dependencies before the first browser run:
uv run playwright install --with-deps chromium
make ui-install ui-build
make test-browser
Metadata
Release files for sqltide 0.46.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sqltide-0.46.0.tar.gz | 1.7 MB | With provenance | Details for sqltide-0.46.0.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| sqltide-0.46.0-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details for sqltide-0.46.0-cp312-abi3-win_amd64.whl |
| sqltide-0.46.0-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ x86-64 | Details for sqltide-0.46.0-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
| sqltide-0.46.0-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ ARM64 | Details for sqltide-0.46.0-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl |
| sqltide-0.46.0-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details for sqltide-0.46.0-cp312-abi3-macosx_11_0_arm64.whl |
| sqltide-0.46.0-cp312-abi3-macosx_10_12_x86_64.whl | CPython 3.12 | abi3 | macOS 10.12+ x86-64 | Details for sqltide-0.46.0-cp312-abi3-macosx_10_12_x86_64.whl |
Total release size: 77.4 MB
Release files / sqltide-0.46.0.tar.gz
| Download URL | sqltide-0.46.0.tar.gz |
|---|---|
| Size | 1.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4903d19e21fe9f7478f4986f842731f87780f8edc5cd3cd1e125c153da65ca59
|
|
BLAKE2b-256 checksum How to use checksums |
4ee3056a541c29167a36dcdd0688106b0d30b57cab147ad367cc98c5a0214312
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logRelease files / sqltide-0.46.0-cp312-abi3-win_amd64.whl
| Download URL | sqltide-0.46.0-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 16.4 MB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
5bd101c5edb1766d2b75a56bed4fbe3cf8f374bfad269f0e369a4a05f1e7b41d
|
|
BLAKE2b-256 checksum How to use checksums |
a023ed1ed216f31cbd15f05b5164e5fade4e7e6c4dcb57acefb4f0c8510a521b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logRelease files / sqltide-0.46.0-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
| Download URL | sqltide-0.46.0-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
|---|---|
| Size | 15.0 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
e5cc4f9c3b67a957ad21cc167d0e783c55044d9aaf2cf35580a53b1a343343d7
|
|
BLAKE2b-256 checksum How to use checksums |
ab4a6cb2071516ab0e5e1631a9094837a277e39705425491ab1a82c2a6226dc0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logRelease files / sqltide-0.46.0-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
| Download URL | sqltide-0.46.0-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl |
|---|---|
| Size | 14.7 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
d5a2ea8d22013f9c929a04d1fc1ccd0fe57fc7a806994c1dbdd52c42291acd18
|
|
BLAKE2b-256 checksum How to use checksums |
412bac7461f24488f28bd4f4f360ecbad71c35abecbb84c2512e2f4dc4b6cc05
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logRelease files / sqltide-0.46.0-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | sqltide-0.46.0-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 14.7 MB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
b0c79f909ef0b77f37797fd5bf46db0d9c382bb0dc938da19dc24204cd12b3e6
|
|
BLAKE2b-256 checksum How to use checksums |
e2d8712b684e0c251b1cb6c59b288e77273a5813fae1d1fd4bc28c06326ffa99
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logRelease files / sqltide-0.46.0-cp312-abi3-macosx_10_12_x86_64.whl
| Download URL | sqltide-0.46.0-cp312-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 15.0 MB |
| Tags | CPython 3.12 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
1090e06984299a7a5a2ab3ce43a1da8d7c6ea4e355ee1679787285fb8bfc70da
|
|
BLAKE2b-256 checksum How to use checksums |
5b1b1747d8b9eebba33efa659b99c8811872cd0dba992b4ee8a2537febbfff29
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logSecurity for sqltide 0.46.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 6 files in this release have been uploaded with provenance metadata.
Attestation for sqltide-0.46.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.