Best Practices
Design patterns and conventions for building maintainable, performant semantic models in Celiq.
This page collects the patterns that consistently produce clean, fast, maintainable Celiq deployments. See also Anti-patterns for the corresponding list of things to avoid.
Semantic model design
One node per grain
Map each node to one physical table at one level of granularity. Avoid mixing row-level and aggregate-level data in the same node.
Do:node: orders # one row per order
dataset: orders
node: order_items # one row per order line
dataset: order_itemsUse descriptive, stable dataset names
Dataset names propagate into CML node definitions. Once a dataset is referenced in production nodes, renaming it requires updating every node. Choose names that will survive schema evolution.
- Use the logical concept, not the table name:
customersnotdim_customers - Use singular nouns:
ordernotorders(though either works โ be consistent) - Avoid warehouse-specific prefixes:
usernotsf_userorprod_user
Keep domains focused
Each domain should answer one business question area. Broad domains with 20+ joins become hard to maintain and generate confusing Discover experiences.
A useful test: if someone opens Discover and picks your domain, can they intuitively find the metric they're looking for in under 30 seconds? If not, split the domain.
Name measures for the business, not the SQL
Measure names are what end users see in Discover and what Orion reads when answering questions. Name them for the business reader:
| SQL instinct | Business name |
|---|---|
sum_revenue | total_revenue |
cnt_orders | order_count |
avg_order_value | average_order_value |
dau | daily_active_users |
Define AI context for Orion
Every node and reveal should have an ai_description that explains what the data represents in plain English. This is the single most impactful thing you can do to improve Orion's answer quality:
node: orders
ai_description: "Contains one row per customer order. Revenue is the net amount after returns and discounts but before shipping."Good descriptions include:
- What each row represents
- How key metrics are calculated (especially non-obvious ones)
- Date fields and their timezone assumptions
- Any known data quirks (e.g. "returns are excluded from this table")
Deployment & environment management
Always have at least two deployments
A Production deployment and a Development deployment are the minimum. This lets you:
- Test new nodes against dev data before promoting to prod
- Validate schema changes in dev before they break prod queries
- Let Weavers experiment without risk
Validate mappings before switching the default deployment
Before promoting a new deployment to default, run Validate All Mappings on every dataset. A deployment with any mapping below 100% compatibility should not become the default.
Keep compatibility at 100% for all production mappings
A compatibility score below 100% means some queries will error. Treat any production mapping below 100% as an incident, not a warning. Common causes:
- A column was renamed or dropped in the warehouse
- A migration ran in the warehouse but the dataset definition wasn't updated
- The wrong physical table was specified
Use database/schema overrides for environment parity
When a single Snowflake or Postgres connection serves multiple environments, use database_override and schema_override on dataset mappings instead of creating separate connections. This reduces credential management overhead.
Query performance
Partition and cluster the tables your nodes use most
Celiq generates standard SQL โ it benefits from the same query optimisations as any SQL tool. For time-series nodes, ensure the primary time column is:
- Partitioned in BigQuery
- Clustered in Snowflake
- Indexed in Postgres (
CREATE INDEX ON orders (created_at))
Avoid high-cardinality dimensions in default fields
When a node has many dimensions, be selective about which are enabled by default in a Reveal. High-cardinality string dimensions (user IDs, email addresses) force Celiq to fetch all values for filter suggestions โ expensive on large tables.
Mark high-cardinality dimensions as hidden: true in the reveal's suggested_attributes list unless specifically needed.
Use rolling window table calculations, not SQL window functions for small datasets
For datasets under ~1M rows with date ordering, use Celiq's client-side table calculations (running total, rolling average) instead of relying on SQL window functions. Client-side calculations let the warehouse return results faster and Celiq applies the window logic after.
For large datasets where you need the window function pushed down to the warehouse, use rolling_average or rolling_sum intent โ these use SQL OVER() clauses.
Security model
Always set Data Keys at the node level, not the domain level
Data Keys (row-level security) should be on the node, not applied ad-hoc in domain joins. This ensures RLS applies regardless of which domain the node is queried through.
Test security rules as a restricted user
After configuring Data Keys and Data Gates, log in as a Tracer-role user (or use sudo mode with a test account) and verify the expected rows and columns are hidden. Security rules that look correct in CML can have subtle bugs that only appear when executing queries.
Use workspaces to separate teams with completely different data access
If two business units should never see each other's data (not just filtered differently), put them in separate workspaces rather than trying to express the separation through Data Keys. Data Keys are for row-level filtering within a team, not complete data isolation between teams.
Governance and collaboration
Certify reveals before sharing them broadly
The certification workflow marks a Reveal as the canonical version of a metric. Certified Reveals appear first in search, get governance badges in the UI, and prevent duplicates from proliferating.
Require certification for any Reveal that:
- Is used in a Mosaic shared with 10+ people
- Is referenced in a scheduled report
- Is cited in a business review or executive summary
Write description fields for all nodes, measures, and dimensions
Descriptions appear as tooltips in Discover and as context for Orion. A node or measure without a description is a documentation gap:
node: orders
description: "All confirmed customer orders. Excludes cancelled and draft orders."
measures:
- name: total_revenue
description: "Net revenue after returns and discounts, in USD. Excludes shipping and tax."Use Evals to prevent regressions
Create Evals for the 10โ20 questions your team asks most frequently. Run them before every semantic model release. A passing eval confirms that semantic changes didn't break Orion's understanding of your most important metrics.
Related pages
- Anti-patterns โ what to avoid
- CML Reference โ complete field reference
- Forge Validation โ the Check & Save gate
- Data Keys โ row-level security
- Evals โ accuracy regression testing