Zero-downtime schema evolution: Auto-migrations for ClickHouse.
Day 06 of the WClickHouse Open-Source Engineering Series.
Managing schema migrations on fast-moving event streams is pure friction. With WClickHouse TableSync, updating your Pydantic model updates ClickHouse.
The Pain Points We Faced
- Writing separate migration files every time an analytics field is added
- Pipeline deployments failing because a new event property has no corresponding column
- Manual ALTER TABLE commands locking teams out of rapid iteration
The Implementation
from typing import Optional from pydantic import BaseModel from wclickhouse import WClickHouse class EventModel(BaseModel): event_id: int name: str # Added new feature in v2: experiment_tag: Optional[str] = None # TableSync automatically adds column! db = WClickHouse(EventModel, db_config) # Output: [SYNC] Added column 'experiment_tag' (Nullable(String)) to table 'eventmodel' Why This Architecture Wins
- TableSync Engine: Compares Pydantic model fields with live ClickHouse table schema.
- Auto ALTER TABLE: Detects missing columns and adds them with correct ClickHouse types.
- Non-Destructive: Never drops existing columns or alters existing data partitions.
Verification & Status
Tested and verified against live ClickHouse server instances with 95%+ test coverage. Built for Python 3.9 through 3.14 with Apache Arrow and Pydantic v2.
![[AWS] Running CI (Integration Testing) for each PR using AWS Emulator [GitHub Actions]](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fqiita-user-contents.imgix.net%2Fhttps%253A%252F%252Fqiita-user-contents.imgix.net%252Fhttps%25253A%25252F%25252Fcdn.qiita.com%25252Fassets%25252Fpublic%25252Farticle-ogp-background-afbab5eb44e0b055cce1258705637a91.png%253Fixlib%253Drb-4.1.1%2526w%253D1200%2526blend64%253DaHR0cHM6Ly9xaWl0YS11c2VyLXByb2ZpbGUtaW1hZ2VzLmltZ2l4Lm5ldC9odHRwcyUzQSUyRiUyRnMzLWFwLW5vcnRoZWFzdC0xLmFtYXpvbmF3cy5jb20lMkZxaWl0YS1pbWFnZS1zdG9yZSUyRjAlMkYxOTI5NDklMkYxYmVjZGE4YTRmMWRiOWU5OTQyZDljOGMwYjZkZDA3NjkwMTM2NjgwJTJGbGFyZ2UucG5nJTNGMTc0MTQ4MzQxMD9peGxpYj1yYi00LjEuMSZhcj0xJTNBMSZmaXQ9Y3JvcCZtYXNrPWVsbGlwc2UmYmc9RkZGRkZGJmZtPXBuZzMyJnM9MDZlM2QxY2EzNTVhN2Y4N2M2ZTQxY2RlYzdmN2M0ODI%2526blend-x%253D120%2526blend-y%253D462%2526blend-w%253D90%2526blend-h%253D90%2526blend-mode%253Dnormal%2526mark64%253DaHR0cHM6Ly9xaWl0YS1vcmdhbml6YXRpb24taW1hZ2VzLmltZ2l4Lm5ldC9odHRwcyUzQSUyRiUyRnMzLWFwLW5vcnRoZWFzdC0xLmFtYXpvbmF3cy5jb20lMkZxaWl0YS1vcmdhbml6YXRpb24taW1hZ2UlMkYxZTIwZGI1ZTdlNDA3ZWFlN2I5NzBlYzk5OTg4MGRjOGMzY2MwZjY0JTJGb3JpZ2luYWwuanBnJTNGMTY2NzI3NDk2Mz9peGxpYj1yYi00LjEuMSZ3PTQ0Jmg9NDQmZml0PWNyb3AmbWFzaz1jb3JuZXJzJmNvcm5lci1yYWRpdXM9OCZiZz1GRkZGRkYmYm9yZGVyPTIlMkNGRkZGRkYmZm09cG5nMzImcz04OTI0NDcwMDk1MDMyZjUxYmZlNzE3ZjVkOGUzYmE3ZA%2526mark-x%253D186%2526mark-y%253D515%2526mark-w%253D40%2526mark-h%253D40%2526s%253D0db13b4aef231a19bc684897cf15021a%3Fixlib%3Drb-4.1.1%26w%3D1200%26fm%3Djpg%26mark64%3DaHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjEuMSZ3PTk2MCZoPTMyNCZ0eHQ9JUUzJTgwJTkwQVdTJUUzJTgwJTkxQVdTJTIwRW11bGF0b3IlRTMlODElQTdQUiVFMyU4MSU5NCVFMyU4MSVBOCVFMyU4MSVBRUNJJUVGJUJDJTg4JUU3JUI1JTkwJUU1JTkwJTg4JUUzJTgzJTg2JUUzJTgyJUI5JUUzJTgzJTg4JUVGJUJDJTg5JUUzJTgyJTkyJUU1JTlCJTlFJUUzJTgxJTk5JUUzJTgwJTkwR2l0SHViQWN0aW9ucyVFMyU4MCU5MSZ0eHQtYWxpZ249bGVmdCUyQ3RvcCZ0eHQtY29sb3I9JTIzMUUyMTIxJnR4dC1mb250PUhpcmFnaW5vJTIwU2FucyUyMFc2JnR4dC1zaXplPTU2JnR4dC1wYWQ9MCZzPTZjNzM1OTE0ZTFiMzFhYjkwMDJlMDhlMTViY2JjMmEw%26mark-x%3D120%26mark-y%3D112%26blend64%3DaHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjEuMSZ3PTgzOCZoPTU4JnR4dD0lNDBOYW5hXzc3NyZ0eHQtY29sb3I9JTIzMUUyMTIxJnR4dC1mb250PUhpcmFnaW5vJTIwU2FucyUyMFc2JnR4dC1zaXplPTM2JnR4dC1wYWQ9MCZzPTg1YzQ4MzUyMmVkMGVhNmYxYjhkZjU5MjVjYzhiNjQz%26blend-x%3D242%26blend-y%3D454%26blend-w%3D838%26blend-h%3D46%26blend-fit%3Dcrop%26blend-crop%3Dleft%252Cbottom%26blend-mode%3Dnormal%26txt64%3DS0RESeOCouOCuOODo-OCpOODq-mWi-eZuuOCu-ODs-OCv-ODvOagquW8j-S8muekvg%26txt-x%3D242%26txt-y%3D539%26txt-width%3D838%26txt-clip%3Dend%252Cellipsis%26txt-color%3D%25231E2121%26txt-font%3DHiragino%2520Sans%2520W6%26txt-size%3D28%26s%3D44bec030dfc5694f973ca7b04acf2d0e)
