Cube — Cubes, Measures, Joins

The headless-BI alternative: cubes in JS/YAML, joins as graph edges, measures as code.

0/2 done

Overview

Cube's bet: BI is an API, not a product

Where the dbt Semantic Layer puts metrics at the top of the abstraction, Cube puts the cube itself — a joinable, multidimensional model — and exposes it as a real API surface (REST, GraphQL, Postgres-wire SQL). The result is a headless BI layer: any consumer that speaks any of those protocols sees the same measures and dimensions.

Anatomy of a cube

cube('Orders', {
  sql: `SELECT * FROM analytics.fct_orders`,

  joins: {
    Users:    { sql: `${CUBE}.user_id    = ${Users}.id`,    relationship: 'belongsTo' },
    Products: { sql: `${CUBE}.product_id = ${Products}.id`, relationship: 'belongsTo' },
  },
  measures: {
    revenue:    { sql: `amount_cents / 100.0`, type: 'sum'   },
    orderCount: { sql: `id`,                   type: 'count' },
    aov:        { sql: `${revenue} / ${orderCount}`, type: 'number' },
  },
  dimensions: {
    country:    { sql: `country`,    type: 'string' },
    productLine:{ sql: `product_line`, type: 'string' },
    orderTs:    { sql: `order_ts`,   type: 'time' },
  },
});

Three things to notice:

  • Joins are first-class graph edges, not buried inside a SELECT. Cube treats the cube graph as a property graph and walks it on demand.
  • Measures can compose (aov references revenue and orderCount) — the metric tree, but expressed inline.
  • Time is a dimension with type: 'time', not a magic column. Granularity (day, week, month, quarter, year) is requested at query time.

LEGO baseplates vs typed function library

Cube is LEGO baseplates for analytics: each cube is a studded plate, joins are the pegs that snap plates together, and dashboards / apps / LLMs are the figurines that stand on top. Snap a new figurine on without rebuilding the city. The dbt SL is more like a typed function library: you call metric('revenue') and the library figures out the joins. Both work; the difference is which abstraction you reach for first.

Reflect

If your team is already in the dbt ecosystem, the dbt SL is the path of least resistance. If your team is API-first / app-first / embedded-analytics-first (or polyglot beyond SQL), Cube's headless model usually fits more naturally. Both are valid; choose by team gravity, not by feature checklist.

  • Is your nearest analytics consumer a BI tool (favours dbt SL) or an embedded React app / LLM (favours Cube)?
  • Which would your developers find more natural to extend — Jinja-templated YAML next to dbt models, or JS/YAML cube files in their own repo?

Reading in progress · 0 of 2 activities done