Skip to main content

What AQL is for

Before we touch pipes, filters, or grouping, it's worth seeing the destination. AQL exists to do one thing well: define metrics once, then query them anywhere.

A metric in 10 lines

A metric is a named, reusable aggregation. Here's one:

metric total_revenue {
label: 'Total Revenue'
type: 'number'
definition: @aql sum(order_items.quantity * products.price) ;;
}

That's it. No GROUP BY, no JOIN, no per-report scaffolding. Just the calculation. The metric travels with its definition.

Same metric, three reports

Drop total_revenue into three different reports and it adapts to each:

// Report 1: no grouping → grand total
explore { measures { total_revenue } }
// → $4,283,512

// Report 2: grouped by country → revenue per country
explore { dimensions { countries.name } measures { total_revenue } }
// → US: $2.1M, UK: $890K, ...

// Report 3: grouped by month, filtered to 2024 → monthly trend
explore {
dimensions { orders.created_at | month() }
measures { total_revenue }
filters { orders.created_at matches @2024 }
}
// → Jan 2024: $312K, Feb 2024: $358K, ...

Same definition. Three different numbers, three different shapes. That's the part SQL can't do cleanly. In SQL you'd write three separate queries with copy-pasted aggregation logic, and any change to "what revenue means" would mean editing all three.

What the rest of Foundations teaches

To write metrics like total_revenue, you need to know the primitives that go inside the definition:

Once those click, the Metrics group covers how metrics interact with related models, how to name and reuse them, and how the surrounding report context shapes what they return.

Next

The pipe operator: the single biggest reason AQL reads differently from SQL.


Open Markdown
Let us know what you think about this document :)