Celiq
v0.12Open app โ†—
Docs/Developer/Migrating from Looker

Migrating from Looker

A practical guide for LookML developers moving to Celiq โ€” concept mapping, CML equivalents, and a step-by-step migration workflow.

LuminaryWeaverUpdated June 2026 ยท 12 min read
โœฆ
In this section
Part of Celiq's semantic layer platform. Connect your warehouse, model your data once, query it everywhere.
๐Ÿ’ก
Tip
What this is: A migration guide for teams moving from Looker to Celiq. It covers concept mapping, LookML-to-CML translation, and a step-by-step migration workflow.
Who it's for: LookML developers, Looker admins, and data engineers who need to reproduce their Looker models in Celiq.
Shortcut: Celiq can auto-import a Looker instance โ€” see Import from Looker or dbt.

If you've built semantic models in Looker, you already understand the core concepts that Celiq implements โ€” views, Explores, dimensions, measures, and row-level security. This guide maps every Looker concept to its Celiq equivalent and walks through a complete migration.

Concept mapping

LookerCeliqNotes
LookML ViewNodeMaps to a table; defines dimensions and measures
LookML ExploreDomainJoin graph; defines valid query starting points
LookMLCMLYAML-based modelling language
Looker IDEForgeSemantic IDE with validation and Git integration
Explore (UI)DiscoverNo-code query builder
Look / Saved ExplorePrismSaved query with visualisation
DashboardMosaicCollection of tiles with auto-refresh
Space / FolderVaultFolder with access controls
user_attribute + access_filterData KeyRow-level security
Column-level securityData GateField-level security
Dev modeDraft modePersonal branch for model changes
Production modeLive modePublished semantic model
LuminaryAdminWorkspace administrator role
WeaverDeveloperModel developer and content creator
TracerStandard userAnalyst with Explore/Discover access
LensViewerRead-only access to shared content
Orion(no equivalent)AI analyst; natural language โ†’ SQL

LookML to CML translation

View โ†’ Node

Looker (LookML):
lookml
view: orders {
  sql_table_name: public.orders ;;

  dimension: order_id {
    type: number
    sql: ${TABLE}.id ;;
  }

  dimension_group: created {
    type: time
    timeframes: [date, week, month, year]
    sql: ${TABLE}.created_at ;;
  }

  measure: total_revenue {
    type: sum
    sql: ${TABLE}.revenue ;;
    value_format_name: usd
  }

  measure: order_count {
    type: count
  }
}
Celiq (CML):
cml
node: orders
  dataset: orders
  dimensions:
    - name: order_id
      type: number
      sql: id
    - name: created_at
      type: time
      grains: [day, week, month, year]
      sql: created_at
  measures:
    - name: total_revenue
      type: sum
      sql: revenue
      format: currency
    - name: order_count
      type: count

Key differences:

  • sql_table_name is replaced by dataset: (referencing a logical dataset)
  • ${TABLE}.field becomes just field (or ${TABLE}.field is also accepted)
  • dimension_group with timeframes becomes a single type: time dimension with grains:
  • type: count works the same โ€” no SQL expression needed

Explore โ†’ Domain

Looker (LookML):
lookml
explore: orders {
  label: "E-commerce Orders"
  join: customers {
    type: left_outer
    sql_on: ${orders.customer_id} = ${customers.id} ;;
    relationship: many_to_one
  }
  join: products {
    type: left_outer
    sql_on: ${orders.product_id} = ${products.id} ;;
    relationship: many_to_one
  }
}
Celiq (CML):
cml
domain: ecommerce
  label: E-commerce Orders
  primary_node: orders
  joins:
    - node: customers
      type: left
      sql: "${orders.customer_id} = ${customers.id}"
      relationship: many_to_one
    - node: products
      type: left
      sql: "${orders.product_id} = ${products.id}"
      relationship: many_to_one

access_filter (RLS) โ†’ Data Key

Looker (LookML):
lookml
explore: orders {
  access_filter: {
    field: orders.customer_region
    user_attribute: region
  }
}
Celiq (CML):
cml
node: orders
  data_keys:
    - field: customer_region
      user_attribute: region

Data Keys apply at the node level, not the domain level. They filter every query against the node, regardless of which domain the query comes from.

always_filter โ†’ default filters

Looker's always_filter applies a filter to all Explore queries. In Celiq, use Filter Mappings on a Reveal, or apply default filters in a Domain's default_filters block (see CML Reference).

Migration workflow

Step 0 โ€” Decide: auto-import vs. manual

Celiq's Import tool can connect to your Looker instance and auto-generate CML nodes and domains from your LookML. This is the fastest path for large models.

Use auto-import when:

  • Your LookML is well-structured with clear view/Explore separation
  • You have more than ~20 views to migrate
  • Your LookML doesn't use heavy PDT (persistent derived tables) logic

Use manual migration when:

  • Your LookML has complex PDTs you need to redesign as nodes with pre-computed datasets
  • You want to use the migration as an opportunity to clean up and simplify the model
  • You want full control over the resulting CML structure

Step 1 โ€” Inventory your Looker model

Before writing any CML:

  1. List every Explore that is actively used (check query counts in Looker's usage data)
  2. For each Explore, list the views it joins
  3. Note any access_filter, sql_always_where, or required_access_grants
  4. Identify PDTs โ€” these need special handling (see below)

Step 2 โ€” Map Explores to Domains

Each Looker Explore becomes one Celiq Domain. The Explore's base view becomes the Domain's primary_node.

If you have Explores that share the same base view but differ only in their joins, you have two options:

  • Create one Domain with all possible joins and let Celiq prune unused ones at query time
  • Create multiple Domains with different join sets (better for large models with performance concerns)

Step 3 โ€” Convert Views to Nodes

For each LookML view:

  1. Create the dataset (Lumen โ†’ Physical Layer โ†’ Datasets) or let Celiq auto-create it when you specify dataset: in the node and validate
  2. Write the CML node, translating:
- dimension โ†’ dimensions block

- measure โ†’ measures block

- dimension_group โ†’ single time dimension with grains:

- sql_table_name โ†’ dataset: field name

Run Check & Save in Forge after each node to catch errors early.

Step 4 โ€” Handle PDTs

Looker PDTs (persistent derived tables) have no direct equivalent in Celiq. Your options:

Option A โ€” materialize in the warehouse: Run the PDT's SQL as a scheduled table refresh in your warehouse (dbt, Airflow, etc.). Create a dataset and node pointing to the materialized table. Option B โ€” use a domain with a derived node: For simpler PDTs (window functions, aggregations), define the logic as a node with sql: expressions. Celiq will compute it at query time. Option C โ€” use CML derived nodes: Celiq supports sql: at the node level for derived columns. Write the derivation logic directly in the node's dimension/measure SQL.

Step 5 โ€” Migrate security rules

For each Looker access_filter, add the equivalent data_keys: block to the corresponding CML node.

For required_access_grants, use Data Gates โ€” field-level visibility controls based on user role.

Step 6 โ€” Rebuild Looks as Prisms

Saved Looks become Prisms in Celiq. For high-priority Looks:

  1. Open Discover and reproduce the query (select the same node/domain, dimensions, measures, filters)
  2. Choose a visualisation and configure it
  3. Save as a Prism
  4. Recreate the folder structure as Vaults

For bulk migration, the Celiq API (POST /api/reveals) can programmatically create Prisms from query specs.

Step 7 โ€” Rebuild Dashboards as Mosaics

Each Looker Dashboard becomes a Mosaic. Add tiles by selecting existing Prisms or creating inline Reveals.

Step 8 โ€” Validate with Evals

Once the model is built, create Evals โ€” prompt sets that test Orion's understanding of your domain. Good evals confirm that the semantic model correctly answers the questions your team actually asks.

Common pitfalls

Looker patternCeliq equivalentWatch out for
${view_name.field} cross-view reference${node_name.field}Node must be in the domain's join graph
type: yesno dimensiontype: boolean dimensionSyntax change only
fanout_onNo direct equivalentDesign joins to avoid fan-out; Forge validation warns on fan-out risk
required_joinsNot needed โ€” Celiq only joins nodes when fields from them are selectedSimpler mental model
extendsNot yet supportedDuplicate the node and modify
set: blocksNot yet supportedManage field visibility with Data Gates