Use Moose with Your Existing ClickHouse
Viewing:
What This Guide Does
This guide sets up a local ClickHouse development environment that mirrors your production database and enables code-first schema management:
- Introspect your remote ClickHouse tables and generate TypeScript/Python data models
- Create a local ClickHouse instance with your exact table schemas
- Seed your local database with production data (optional)
- Build APIs and pipelines on top of your ClickHouse data in code
How It Works
Local Development:
- Your production ClickHouse remains untouched
- You get a local ClickHouse instance that copies your remote table schemas
- All development happens locally with hot-reload
Production Deployment:
- When you deploy your code, it connects to your remote ClickHouse
- Any new tables, materialized views, or schema changes you create in code are automatically migrated to your target database
- Your existing data and tables remain intact
What You Get
Schema management in code
Define ClickHouse tables, materialized views, and schemas as TypeScript/Python code
Auto-generated models
TypeScript/Python classes generated from your existing ClickHouse tables
Local development environment
Local ClickHouse instance that mirrors your production schema
Type-safe APIs
Build REST APIs with full type safety and autocomplete
Automatic migrations
Schema changes are automatically applied to your target database on deployment
Prerequisites
Before you start
Existing ClickHouse Database
Any ClickHouse instance (Cloud, self-hosted, or playground)
Node.js 20+
Required for TypeScript development
Download →Docker Desktop
For local development environment
Download →macOS/Linux
Windows works via WSL2
Before you start
Existing ClickHouse Database
Any ClickHouse instance (Cloud, self-hosted, or playground)
Python 3.12+
Required for Python development
Download →Docker Desktop
For local development environment
Download →macOS/Linux
Windows works via WSL2
Step 1: Install Moose
Install the Moose CLI globally to your system:
bash -i <(curl -fsSL https://fiveonefour.com/install.sh) moose
What happens next
After installation, you’ll use moose init
to create a new project that automatically connects to your ClickHouse and generates all the code you need.
Step 2: Create Your Project
Don't have ClickHouse?
Use the ClickHouse Playground tab to try it out!
# Option 1: Provide connection string directly
moose init my-project --from-remote <YOUR_CLICKHOUSE_CONNECTION_STRING> --language typescript
# Option 2: Run without connection string for interactive setup
moose init my-project --from-remote --language typescript
# Option 1: Provide connection string directly
moose init my-project --from-remote <YOUR_CLICKHOUSE_CONNECTION_STRING> --language python
# Option 2: Run without connection string for interactive setup
moose init my-project --from-remote --language python
Connection String Format:
https://username:password@host:port/?database=database_name
Interactive Setup
If you don’t provide a connection string, Moose will guide you through an interactive setup process where you’ll be prompted to enter:
- Host and port (e.g.,
https://your-service-id.region.clickhouse.cloud:8443
) - Username (usually
default
) - Password (your ClickHouse password)
- Database name (optional, defaults to
default
)
This is perfect if you’re not sure about your connection details or prefer a guided experience.
Moose will create a complete project structure with:
- Data models: TypeScript/Python classes for every table in your ClickHouse
- Type definitions: Full type safety for all your data
- Development environment: Local ClickHouse instance that mirrors your production schema
- Build tools: Everything configured and ready to go
cd my-project
npm install
cd my-project
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
You should see: Successfully generated X models from ClickHouse tables
Explore Your Generated Models
Check what Moose created from your tables in the app/main.py
file:
- main.py
Import Pattern
Check what Moose created from your tables in the app/index.ts
file:
- index.ts
Export Pattern
If your database includes ClickPipes/PeerDB (CDC) tables
As noted above, when you use moose init --from-remote
, Moose introspects your database. If it detects CDC‑managed tables (e.g., PeerDB/ClickPipes with fields like _peerdb_synced_at
, _peerdb_is_deleted
, _peerdb_version
), it marks those as EXTERNALLY_MANAGED
and writes them into a dedicated external models file. Your root file is updated to load these models automatically.
- index.ts
- externalModels.ts
- main.py
- external_models.py
This separation is a best‑effort by the CLI to keep clearly CDC‑owned tables external. For other tables you don’t want Moose to manage, set the lifecycle to external and move them into the external file. See:
- External Tables documentation for more information on how external tables work.
- DB Pull for keeping models in sync with the remote schema.
Step 3: Start Development
Start your development server. This spins up a local ClickHouse instance that perfectly mirrors your production schema:
moose dev
What happens when you run moose dev
:
- 🏗️ Creates a local ClickHouse instance with your exact table schemas in your project code
- 🔄 Hot-reloads migrations to your local infrastructure as you save code changes
- 🚀 Starts a web server for building APIs
Your production ClickHouse remains completely untouched. This is a separate, local development environment.
Seed Your Local Database (Optional)
Copy real data from your production ClickHouse to your local development environment. This gives you realistic data to work with during development.
Why seed? Your local database starts empty. Seeding copies real data so you can:
- Test with realistic data volumes
- Debug with actual production data patterns
- Develop features that work with real data structures
moose seed clickhouse --connection-string <YOUR_CLICKHOUSE_CONNECTION_STRING> --limit 100000
Connection String Format: The connection string must use ClickHouse native protocol:
# ClickHouse native protocol (secure connection)
clickhouse://username:password@host:9440/database
Note: Data transfer uses ClickHouse’s native TCP protocol via remoteSecure()
. The remote server must have the native TCP port accessible. The command automatically handles table mismatches gracefully.
Notes
--limit
and--all
are mutually exclusive--all
can be used to copy the entire table(s), use with caution as it can be very slow and computationally intensive.- Large copies are automatically batched to avoid remote limits; you’ll see per-batch progress.
- If you stop with Ctrl+C, the current batch finishes and the command exits gracefully.
Expected Output:
✓ Database seeding completed
Seeded 'local_db' from 'remote_db'
✓ table1: copied from remote
⚠️ table2: skipped (not found on remote)
✓ table3: copied from remote
Troubleshooting:
- Tables that don’t exist on remote are automatically skipped with warnings
- Use
--table <name>
to seed a specific table that exists in both databases - Check
moose ls table
to see your local tables
Step 4: Build Your First API
Now that you have your data models, let’s build something useful! You can create APIs, materialized views, and applications with full type safety.
What you can build
- REST APIs that expose your ClickHouse data to frontend applications
- Materialized Views for faster queries and aggregations
- Streaming pipelines for real-time data processing
- Full-stack applications with your ClickHouse data as the backend
Add APIs
Build REST APIs on top of your existing tables to expose your data to your user-facing apps. This is a great way to get started with Moose without changing any of your existing pipelines.
import { TargetSchema, materializedView } from "./myMaterializedView";
export interface QueryParams {
date: Date;
limit?: number;
}
const api = new Api<QueryParams, TargetSchema>("get-aggregated-data",
async ({ date, limit = 10 }: QueryParams, { client, sql }) => {
const query = sql`
SELECT * FROM ${materializedView.targetTable}
WHERE date = ${date}
LIMIT ${limit}`;
const result = await client.query.execute<TargetSchema>(query); // Type-safe query execution
return result.json();
}
);
Building APIs with Moose
Check out the MooseAPI module for more information on building APIs with Moose.
Build Materialized Views
Build materialized views on top of your existing tables to improve query performance. If you have Materialized Views in your ClickHouse, you can use Moose to build new Materialized Views on top of your existing tables, or to migrate your existing Materialized Views to Moose.
// Data Model for your Materialized View- use type throughout your codebase
export interface TargetSchema {
date: Date;
count: number;
}
// Creates both the target table and the materialized view
export const materializedView = new MaterializedView<TargetSchema>({
// Raw SQL with type-safe table references
selectStatement: sql`SELECT count(*) as count, date FROM ${myTable} GROUP BY date`,
selectTables: [myTable], // Automatic dependency resolution for cascading materialized views
engine: ClickHouseEngines.MergeTree, // Can use which ever engine you want
orderByFields: ["date"],
tableName: "myAggregation",
materializedViewName: "myAggregation_MV",
});
Known Limitations
Early Access Feature
Some advanced ClickHouse features may not be fully supported yet. Join the Moose Slack and let us know if you have any issues, feedback, or requests.
What we’re working on:
- Selective table import (currently imports all tables)
- Default value annotations
Troubleshooting
Error: Failed to connect to ClickHouse
This guide shows exactly where to find your host, port, username, and password, and how to construct a valid HTTPS connection string.
- Log into your ClickHouse Cloud console
- Open your service details page
- Click “Connect” in the sidebar

- Select the
HTTPS
tab and copy the values shown- Host: e.g.
your-service-id.region.clickhouse.cloud
- Port: usually
8443
- Username: usually
default
- Password: the password you configured
- Host: e.g.

- Build your connection string:
https://USERNAME:PASSWORD@HOST:PORT/?database=DATABASE_NAME
- Example (with placeholders):
https://default:your_password@your-service-id.region.clickhouse.cloud:8443/?database=default
- Optional: Test with curl
curl --user "USERNAME:PASSWORD" --data-binary "SELECT 1" https://HOST:PORT
moose dev
fails to start
Double check Docker is running and you do not have any port conflicts.
- ClickHouse local runs on port
18123
- Your local webserver runs on port
4000
- Your local management API runs on port
5001