Metrics as code.

A language for defining and querying business metrics. Write once, get consistent answers everywhere.

How It Works

1

Define

Model your tables, metrics, and dimensions in readable syntax

 metric revenue = [orders:
sum(amount)
]
dimension channel = [orders: utm_source]
2

Query

Write natural queries with filters, groupings, and transforms

 filter channel where revenue.top(5)
select revenue.percent by channel 
3

Execute

Get optimized SQL and results for any database

 -- Compiles to optimized SQL WITH ranked AS (
SELECT utm_source, revenue,
ROW_NUMBER() OVER (...)
  ...
)

Why Dictum

๐Ÿ“

Readable syntax

Not YAML, not raw SQL. A language designed for metrics that humans can read and review.

๐Ÿ”„

Version controlled

Definitions live in code. Review changes in PRs, track history, roll back mistakes.

โšก

Editor support

LSP integration for autocomplete, inline errors, and hover documentation.

๐Ÿ—„๏ธ

Multi-database

Works with DuckDB, ClickHouse, PySpark/Databricks. PostgreSQL, BigQuery, Snowflake coming soon.

๐Ÿ”—

Automatic joins

Define relationships once. Dictum resolves join paths automatically.

๐Ÿ“Š

Built-in transforms

.percent, .total, .top(N), .diff_percent โ€” common analytics patterns built in.

Complete Example

# Define your metrics
metric revenue = [orders: sum(amount)]
metric orders = [orders: count(*)]
metric aov = revenue / orders  # derived metric

# Define dimensions
dimension channel = [orders: utm_source]
dimension country = [orders: customer.country]
dimension plan = [orders: customer.plan_name]

# Define table relationships
table orders
  joins customers as customer using (customer_id),
        products using (product_id)

# Query: Top channels by revenue with AOV
filter channel where revenue.top(5)
select revenue, revenue.percent, aov
by channel
with orders_75102368 as (
    select
        orders.utm_source as channel,
        sum(orders.amount) as revenue_75102368,
        count(*) as orders_75102368
    from orders as "orders"
    group by
        orders.utm_source
    order by sum(orders.amount) desc, orders.utm_source asc
    limit 5
),
orders_24912fa3 as (
    select
        orders.utm_source as channel,
        sum(orders.amount) as revenue_24912fa3
    from orders as "orders"
    group by
        orders.utm_source
),
merge_000c08a5 as (
    select
        orders_24912fa3.channel as channel,
        row_number() over (order by orders_24912fa3.revenue_24912fa3 desc, orders_24912fa3.channel asc) <= 5 as revenue
    from orders_24912fa3 as "orders_24912fa3"
),
orders_a0ee069b as (
    select
        sum(orders.amount) as revenue_a0ee069b
    from orders as "orders"
    where exists (select 1 from merge_000c08a5 where merge_000c08a5.revenue and merge_000c08a5.channel = orders.utm_source)
)
select
    coalesce(orders_75102368.channel, orders_75102368.channel, orders_75102368.channel, orders_75102368.channel) as channel,
    orders_75102368.revenue_75102368 as revenue,
    orders_75102368.revenue_75102368 / orders_a0ee069b.revenue_a0ee069b as revenue__percent,
    orders_75102368.revenue_75102368 / orders_75102368.orders_75102368 as aov
from orders_75102368 as "orders_75102368"
left join orders_a0ee069b as orders_a0ee069b
    on true
order by channel

Ready to try it?

Start writing metrics in the interactive playground