← Back to overview The interface

Ask for the number. We write the SQL.

A Semantic Query is a structured object — metrics × dimensions × filters × grain. Every consumer emits the same shape; the compiler turns it into correct, dialect-specific SQL.

One Semantic Query, any warehouse dialect A Semantic Query names metrics, dimensions, filters, and a grain. The compiler resolves the Join Graph, keeps aggregation fan-out-safe, and renders dialect-specific SQL — the same request produces correct SQL whether the source is Snowflake, BigQuery, Postgres, MySQL, or DuckDB. Semantic Query metrics × dimensions × filters × grain Compiler resolves the Join Graph keeps aggregation fan-out-safe renders per dialect Snowflake BigQuery Postgres MySQL DuckDB
The compiler is the only thing that knows SQL dialects exist — every consumer sends the same Semantic Query shape, regardless of which warehouse answers it.
semantic-query.json what you send

  "metrics": ["average_order_value"],
  "dimensions": ["customer.region"],
  "grain": "month",
  "filters": [
    "field": "order.status",
    "op": "=", "value": "paid"
  ],
  "order": ["month"],
  "limit": 100


// no joins. no aggregation.
// no dialect. no rollup names.
compiled.sql what we run
-- fan-out-safe · Join Graph resolved
-- served from a covering rollup
SELECT
  date_trunc('month', o.order_date) AS month,
  c.region,
  SUM(o.amount) / NULLIF(COUNT(o.id),0)
    AS average_order_value
FROM rollup_orders o
JOIN dim_customer c
  ON o.customer_key = c.customer_key
WHERE o.status = 'paid'
GROUP BY 1, 2
ORDER BY 1
LIMIT 100;

average_order_value is a Metric — a ratio of two Measures computed after aggregation, not avg(amount). region lives on Customer; the compiler walks Order → Customer to reach it. You just listed them.

See it end to end

See why this stays sub-second.

The compiler is one half of the story — the hot path serving this from a rollup instead of the warehouse is the other.