AMQL Docs
Writing AQL

Where to define AQL expressions

Decide whether an AQL metric or dimension belongs on a model, on a dataset, as a standalone Metric, or inline in an explore.

You can write AQL in four places: on a model, on a dataset, as a standalone Metric, or inline inside an explore block. The right home depends on scope (which models the expression touches) and reusability (who else needs it).

Decision table

TypeExampleBest homeWhy
Simple aggregation / single-model metricTotal ordersModel: measureCalculation lives where the data does; reusable wherever the model is reused
Single-model dimension transformAge group from users.ageModel: dimensionTravels with the model
Cross-model metricRevenue per userDataset: metricNeeds the dataset's relationships to join
Cross-model dimensionCustomer segment based on purchasesDataset: dimensionSame reason: needs the join graph
Metric reused across multiple datasetsGMV shared by Sales, Finance, and Marketing datasetsStandalone MetricDefined once, attached to any dataset via extend
One-off analysisQ4 sales spike investigationAd-hoc in explorationNot worth persisting

How the four placements compare

Model measure / dimensionDataset metric / dimensionStandalone MetricAd-hoc in exploration
ScopeOne modelMultiple models in the datasetAny dataset that includes itSingle exploration
Reuses across datasets✅ Wherever the model is used❌ Bound to one dataset✅ Attach to any dataset❌ Single exploration
Visible to end users✅✅✅ Once attached to a datasetOnly the exploration's viewers
Persists✅ In source-controlled AML✅ In source-controlled AML✅ In source-controlled AMLOnly if saved as a report
Who editsData team (modeling layer)Data team (modeling layer)Data team (modeling layer)Anyone with explore access

On a model

When the calculation only touches one model, put it on the model (as a measure for aggregation, or dimension for per-row transform). It then travels with the model wherever it's reused.

Model orders {
  data_source_name: 'main'

  dimension id { type: 'number', primary_key: true }
  dimension amount { type: 'number' }
  dimension status { type: 'text' }
  dimension created_at { type: 'datetime' }

  // Aggregation → measure
  measure total_revenue {
    type: 'number'
    definition: @aql sum(orders.amount) ;;
  }

  // Per-row transform → dimension
  dimension is_completed {
    type: 'truefalse'
    definition: @aql orders.status == 'completed' ;;
  }
}

On a dataset

When the expression spans multiple models, define it at the dataset level. The dataset is where the relationships live, so it's the only place AQL can resolve cross-model joins.

Dataset ecommerce {
  models: [orders, order_items, products, users]
  relationships: [
    relationship(order_items.order_id  > orders.id, true),
    relationship(order_items.product_id > products.id, true),
    relationship(orders.user_id        > users.id, true),
  ]

  metric revenue_per_user {
    type: 'number'
    definition: @aql
      safe_divide(
        order_items | sum(order_items.quantity * products.price),
        count_distinct(users.id)
      )
    ;;
  }

  dimension customer_segment {
    model: users
    type: 'text'
    definition: @aql
      case(
        when: (sum(orders.amount) | dimensionalize(users.id)) > 10000, then: 'VIP',
        when: (sum(orders.amount) | dimensionalize(users.id)) > 1000,  then: 'Regular',
        else: 'New'
      )
    ;;
  }
}

As a standalone Metric

When the same metric is needed across multiple datasets, declare it as a top-level Metric object. The definition lives independently of any dataset, and each dataset attaches it via extend. Change the definition once, and every dataset that references it picks up the update.

metrics.aml
Metric gmv {
  label: "GMV (Gross Merchandise Value)"
  type: "number"
  definition: @aql order_items | sum(order_items.quantity * products.price) ;;
  format: "[\$\$]#,###0"
}

Metric total_orders {
  label: "Total Orders"
  type: "number"
  definition: @aql count(orders.id) ;;
}

Then attach the standalone metrics to any dataset that needs them:

sales.dataset.aml
Dataset sales_with_metrics = sales.extend({
  metric gmv: gmv
  metric total_orders: total_orders
})

The same gmv definition can be attached to a finance dataset, a marketing dataset, and so on. It's a single source of truth for the calculation. For organizing groups of related metrics (e.g. a thematic PartialDataset of finance metrics), see Implement Reusable Metric Store.

Inline in an explore

For a one-off question, write the AQL directly as a measure of the explore block. Nothing is saved to the model, so the expression lives only as long as the query. Good for quick analysis, and for trying a definition before promoting it to a model or dataset.

explore {
  dimensions { products.category }
  measures {
    delivered_revenue: sum(order_items.quantity * products.price) | where(orders.status == 'delivered')
  }
}

See also

On this page