Skip to main content

clickhouse-alembic

Alembic-based migrations for ClickHouse, optimized for ClickHouse Cloud.

What is ch-migrate?

ch-migrate is a CLI tool for managing ClickHouse schema migrations. It:

  • Initializes project structure with config files
  • Bootstraps databases with proper roles and users
  • Runs Alembic migrations against ClickHouse

Features

  • Multi-environment support - Manage dev, staging, and production with separate configs
  • ClickHouse Cloud compatible - Uses standard engines (auto-upgraded to Shared* on Cloud), handles non-transactional DDL
  • Role-based access control - Creates roles for migration, read-only (MCP), and dictionary access
  • Object-centric SQL history - Track all versions of each table/view/dictionary
  • Zero-downtime migrations - EXCHANGE TABLES pattern for safe schema changes
  • Bootstrap command - One-command database and user setup (idempotent)
  • SSM support - Store credentials in AWS SSM Parameter Store
  • YAML + env vars - Config in version control, secrets in environment

Quick Start

Installation

The package on PyPI is clickhouse-alembic; the command it installs is ch-migrate.

For CLI usage (recommended for most users):

# Install globally - ch-migrate available everywhere
uv tool install clickhouse-alembic

# Verify installation
ch-migrate --version

As a project dependency (for importing in Python code):

uv add clickhouse-alembic
uv run ch-migrate --version

# Or with pip
pip install clickhouse-alembic

Pin to a specific version:

uv tool install clickhouse-alembic==0.4.1

Unreleased changes from main:

uv tool install git+https://github.com/DRYCodeWorks/clickhouse-migrate.git

Initialize a Project

# Create a new project
mkdir my-clickhouse-project
cd my-clickhouse-project

# Initialize with ch-migrate
ch-migrate init

# Or initialize in current directory with custom name
ch-migrate init --name my_project

This creates:

my-clickhouse-project/
├── config.yaml              # ClickHouse hosts and settings
├── .env.local.example       # Template for secrets
├── .gitignore
├── alembic.ini
└── migrations/
    ├── env.py
    ├── script.py.mako
    ├── versions/            # Migration files go here
    └── sql/
        ├── bootstrap/
        └── history/
            ├── tables/
            ├── views/
            └── dictionaries/

Configure

  1. Edit config.yaml with your ClickHouse hosts:
project:
  name: my_project

defaults:
  port: 8443
  secure: true
  admin_user: default
  # Optional users (uncomment to enable):
  # dict_reader_name: dict_reader
  # mcp_user_name: mcp_reader

environments:
  dev:
    host: my-dev-instance.clickhouse.cloud
    database: my_project_dev
    migration_user: migration_dev

  production:
    host: my-prod-instance.clickhouse.cloud
    database: my_project
    migration_user: migration_prod
  1. Set up credentials (choose one):

Option A: Environment file

cp .env.local.example .env.local
# Edit with your passwords:
CH_DEV_MIGRATION_PASSWORD=your-dev-password
CH_DEV_ADMIN_PASSWORD=your-dev-admin-password

Option B: AWS SSM (for production)

# In config.yaml, add ssm paths:
environments:
  production:
    host: my-prod-instance.clickhouse.cloud
    database: my_project
    migration_user: migration_prod
    ssm:
      admin_password: /my_project/prod/admin_password
      migration_password: /my_project/prod/migration_password

Bootstrap Database

# Creates database, roles, and users
ch-migrate bootstrap dev

# Preview without executing
ch-migrate bootstrap dev --dry-run

Create and Run Migrations

# Create a new migration
ch-migrate new dev create_users_table

# Run pending migrations
ch-migrate up dev

# Check status
ch-migrate status dev

# Rollback last migration
ch-migrate down dev

# Show history
ch-migrate history dev

Migration Patterns

Basic Table Creation

  1. Create SQL file in migrations/sql/history/tables/users/001_<revision>.sql:
CREATE TABLE {db}.users (
    id UInt64,
    email String,
    name String,
    created_at DateTime DEFAULT now()
)
ENGINE = MergeTree
ORDER BY id
  1. Reference in migration:
from alembic import op
from clickhouse_alembic import get_db, read_sql

def upgrade():
    db = get_db()
    op.execute(read_sql("history/tables/users/001_abc123.sql", db=db))

def downgrade():
    db = get_db()
    op.execute(f"DROP TABLE IF EXISTS {db}.users")

Zero-Downtime Schema Changes

Use EXCHANGE TABLES for data-preserving migrations:

def upgrade():
    db = get_db()

    # 1. Create new table with updated schema
    op.execute(read_sql("history/tables/users/002_def456.sql", db=db)
               .replace(f"{db}.users", f"{db}.users_new"))

    # 2. Migrate data with transformations
    op.execute(f"""
        INSERT INTO {db}.users_new
        SELECT id, email, name, created_at, '' as phone
        FROM {db}.users
    """)

    # 3. Atomic swap
    op.execute(f"EXCHANGE TABLES {db}.users AND {db}.users_new")

    # 4. Drop old table
    op.execute(f"DROP TABLE {db}.users_new")

Dictionary with Auto-Grant

from clickhouse_alembic import create_dictionary

def upgrade():
    # Automatically grants SELECT to dict_reader on source table
    create_dictionary("history/dictionaries/dict_users/001_abc123.sql")

CLI Reference

# Initialize new project
ch-migrate init [PATH] [--name NAME]

# Bootstrap database (create DB, roles, users)
ch-migrate bootstrap <environment> [--dry-run]

# Apply pending migrations
ch-migrate up <environment>

# Rollback last migration
ch-migrate down <environment> [--revision REV]

# Show current status
ch-migrate status <environment>

# Show migration history
ch-migrate history <environment>

# Create new migration
ch-migrate new <environment> <name>

Configuration Reference

config.yaml

project:
  name: my_project          # Project identifier

defaults:                   # Inherited by all environments
  port: 8443
  secure: true
  admin_user: default
  # dict_reader_name: dict_reader    # Uncomment to enable
  # mcp_user_name: mcp_reader        # Uncomment to enable

environments:
  dev:
    host: dev.clickhouse.cloud
    database: my_project_dev
    migration_user: migration_dev
    # SSM paths (optional, if set fetches from SSM directly):
    # ssm:
    #   admin_password: /my_project/dev/admin_password
    #   migration_password: /my_project/dev/migration_password

Environment Variables

Variable Required Description
CH_<ENV>_MIGRATION_PASSWORD Yes Migration user password
CH_<ENV>_ADMIN_PASSWORD For bootstrap Admin password for creating users
CH_<ENV>_DICT_READER_PASSWORD If dict_reader enabled dict_reader user password
CH_<ENV>_MCP_PASSWORD If mcp_user enabled MCP user password

Legacy CH_<ENV>_PASSWORD is supported for backward compatibility.

Roles and Users

Bootstrap creates the following roles:

Role Purpose
{project}_migration_role Full migration access, including explicit system.grants introspection (required)
{project}_readonly_role Read-only for MCP tools (optional)
{project}_dict_role Dictionary source access (optional)

ClickHouse Cloud Notes

  • Uses standard engines (MergeTree, ReplacingMergeTree) - auto-upgraded to Shared* variants on Cloud
  • Native port 9440 maps to HTTP port 8443
  • No transactional DDL - migrations can't be atomically rolled back
  • Each op.execute() runs one statement (no multi-statement batches)

License

MIT License - see LICENSE file for details.

Author

Dan Young

Metadata

Release files for clickhouse-alembic 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for clickhouse-alembic 0.4.1
File Size Uploaded Provenance
clickhouse_alembic-0.4.1.tar.gz 78.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for clickhouse-alembic 0.4.1
File Interpreter ABI Platform
clickhouse_alembic-0.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 143.7 kB

Release files / clickhouse_alembic-0.4.1.tar.gz

Download URL clickhouse_alembic-0.4.1.tar.gz
Size 78.8 kB
Tags Source
SHA-256 checksum
How to use checksums
796b087428361f6f620422187c03cc75212c8370ed79b1f090a4c3a8908311cb
BLAKE2b-256 checksum
How to use checksums
9c3b92609000b003b47ab9836d3c6b1434aa04956a5a9383b9858aeec9dd5cc4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 2, 2026.

Transparency log

Release files / clickhouse_alembic-0.4.1-py3-none-any.whl

Download URL clickhouse_alembic-0.4.1-py3-none-any.whl
Size 64.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cc906c5dd6288e8973eccdc867e5a0949041a775f8f5b35df7b282ff3916f473
BLAKE2b-256 checksum
How to use checksums
8e565d697b34d7ff50efa54cb29d3e67907596b621f54ee325fcbb15de779f5f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 2, 2026.

Transparency log

Security for clickhouse-alembic 0.4.1

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 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for clickhouse_alembic-0.4.1.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 2, 2026.

Transparency log

A 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.

Release history Release notifications | RSS feed

This release

0.4.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page