All types support nullable variants using optional syntax. Nullable columns can store NULL values.
Nullable columns require a separate null bitmap that ClickHouse checks on every row access. This overhead applies even if only one row contains NULL. For frequently-queried columns, prefer using default values (e.g., 0, "", or a sentinel value) instead of Nullable.
from typing import Optional class User(BaseModel): name: str # Required - NOT NULL email: Optional[str] = None # Nullable(String) age: Optional[int] = None # Nullable(Int64) verified: Optional[bool] = None # Nullable(Boolean)If a field is optional but you provide a ClickHouse default, Moose creates a non-nullable column with a clause instead of a column.
DEFAULTNullablefrom typing import Optional, Annotatedfrom moose_lib import clickhouse_default class User(BaseModel): name: str # Optional without default → Nullable(Int64) age: Optional[int] = None # Optional with default → Int64 DEFAULT 18 (non-nullable) min_age: Annotated[Optional[int], clickhouse_default("18")] = None # String with default status: Annotated[Optional[str], clickhouse_default("'active'")] = None| Pattern | TypeScript | Python | ClickHouse Result |
|---|---|---|---|
| Required | field: T | field: T | T NOT NULL |
| Optional | field?: T | Optional[T] = None | Nullable(T) |
| Optional + Default | field?: T & ClickHouseDefault<"val"> | Annotated[Optional[T], clickhouse_default("val")] | T DEFAULT val |
ClickHouse defaults are SQL expressions. String defaults must include quotes: "'active'" not "active". Numeric defaults are bare: "18" not "'18'".