External tables allow you to connect Moose to database tables that are managed outside of your application. This is essential when working with:
When schema is controlled by services like ClickPipes, Debezium, or AWS DMS
Connecting to existing tables managed by other teams or systems
Working with data sources where you don't control schema evolution
Environments with formal database change approval processes
Set lifeCycle: LifeCycle.EXTERNALLY_MANAGED to tell Moose not to modify the table schema:
import { OlapTable, LifeCycle } from "@514labs/moose-lib"; interface CdcUserData { id: string; name: string; email: string; updated_at: Date;} // Connect to CDC-managed tableconst cdcUserTable = new OlapTable<CdcUserData>("cdc_users", { lifeCycle: LifeCycle.EXTERNALLY_MANAGED});Set lifeCycle: LifeCycle.EXTERNALLY_MANAGED to tell Moose not to modify the table schema:
import { OlapTable, LifeCycle } from "@514labs/moose-lib"; interface CdcUserData { id: string; name: string; email: string; updated_at: Date;} // Connect to CDC-managed tableconst cdcUserTable = new OlapTable<CdcUserData>("cdc_users", { lifeCycle: LifeCycle.EXTERNALLY_MANAGED});If you don't yet have a Moose project, use init-from-remote to bootstrap models from your existing ClickHouse:
moose init my-project --from-remote <YOUR_CLICKHOUSE_URL> --language <typescript|python>What happens:
EXTERNALLY_MANAGED and writes them into a dedicated external models file:
app/externalModels.tsapp/external_models.pyHow detection works (ClickPipes/PeerDB example):
_peerdb_synced_at, _peerdb_is_deleted, _peerdb_version, and related metadata columns.EXTERNALLY_MANAGED and emitted into the external models file automatically.import { OlapTable, LifeCycle, ClickHouseEngines } from "@514labs/moose-lib";import type { ClickHouseInt, ClickHouseDecimal, ClickHousePrecision, ClickHouseDefault } from "@514labs/moose-lib";import typia from "typia"; export interface foo { id: string & typia.tags.Format<"uuid">; name: string; description: string | undefined; status: string; priority: number & ClickHouseInt<"int32">; is_active: boolean; metadata: string | undefined; tags: string[]; score: (string & ClickHouseDecimal<10, 2>) | undefined; large_text: string | undefined; created_at: string & typia.tags.Format<"date-time"> & ClickHousePrecision<6>; updated_at: string & typia.tags.Format<"date-time"> & ClickHousePrecision<6>; _peerdb_synced_at: string & typia.tags.Format<"date-time"> & ClickHousePrecision<9> & ClickHouseDefault<"now64()">; _peerdb_is_deleted: number & ClickHouseInt<"int8">; _peerdb_version: number & ClickHouseInt<"int64">;} export const FooTable = new OlapTable<foo>("foo", { orderByFields: ["id"], engine: ClickHouseEngines.ReplacingMergeTree, ver: "_peerdb_version", settings: { index_granularity: "8192" }, lifeCycle: LifeCycle.EXTERNALLY_MANAGED,});If there are other tables in your DB that are not CDC-managed but you want Moose to treat as external (not managed by code):
// In a file you control (not the external file yet)const table = new OlapTable<MySchema>("my_table", { lifeCycle: LifeCycle.EXTERNALLY_MANAGED});app/externalModels.ts or app/external_models.py).import "./externalModels"; (TypeScript) or from external_models import * (Python) in your app/index.ts (TypeScript) or app/main.py (Python) file.This keeps truly external tables out of your managed code path, while still making them available locally (and in tooling) without generating production DDL.
EXTERNALLY_MANAGED tables reflect schemas owned by your CDC/DBA/ETL processes. Do not change their field shapes in code.
If you accidentally edited an external model, revert to the source of truth by running DB Pull: /moosestack/olap/db-pull.
Locally, externally managed tables are created/kept in sync in your development ClickHouse so you can develop against them and seed data. See Seed (ClickHouse) in the CLI: /moosestack/moose-cli#seed-clickhouse.
Moose will not apply schema changes to EXTERNALLY_MANAGED tables in production. If you edit these table models in code, those edits will not produce DDL operations in the migration plan (they will not appear in plan.yaml).
For more on how migration plans are generated and what shows up in plan.yaml, see /moosestack/olap/planned-migrations.
For EXTERNALLY_MANAGED tables, keep your code in sync with the live database by running DB Pull. You can do it manually or automate it in dev.
moose db pull --clickhouse-url <YOUR_CLICKHOUSE_URL>Use DB Pull to regenerate your external models file from the remote schema. To run it automatically during development, see the script hooks in the local development guide.