Skip to content
Telemetry
Revenue and billing SQL recipe

Calculate net and gross revenue retention

Calculate NRR and GRR from account-level monthly recurring-revenue snapshots while keeping expansion out of gross retention.

Intermediateaccount_mrr_snapshotsReviewed 2026-07-28Tested with Apache DataFusion 45.2.0

Reviewed by the Telemetry product team on . We checked the SQL syntax, required event fields, sample results, and limits on using the query. Who reviews this page

Question answered

How much starting recurring revenue was retained before and after expansion?

Net retention includes expansion. Gross retention caps each account at its starting value. Compare both to see how much revenue you retained and how much came from upsells.

Event schema

Fields the query expects

FieldTypeWhy it exists
timestamp_utcTimestampMonth-end snapshot time.
account_idUtf8Stable billing account identifier.
starting_mrr_usdFloat64MRR at the beginning of the measurement month.
ending_mrr_usdFloat64MRR at the end of the measurement month.
DataFusion SQL

Copy the query

sql
SELECT
  date_trunc('month', timestamp_utc) AS month,
  COUNT(*) AS starting_accounts,
  SUM(starting_mrr_usd) AS starting_mrr_usd,
  SUM(ending_mrr_usd) AS ending_mrr_usd,
  100.0 * SUM(ending_mrr_usd)
    / NULLIF(SUM(starting_mrr_usd), 0) AS net_revenue_retention_pct,
  100.0 * SUM(CASE
    WHEN ending_mrr_usd < 0.0 THEN 0.0
    WHEN ending_mrr_usd > starting_mrr_usd THEN starting_mrr_usd
    ELSE ending_mrr_usd
  END) / NULLIF(SUM(starting_mrr_usd), 0)
    AS gross_revenue_retention_pct
FROM account_mrr_snapshots
WHERE timestamp_utc >= now() - INTERVAL '12 months'
  AND starting_mrr_usd > 0.0
GROUP BY date_trunc('month', timestamp_utc)
ORDER BY month;

This read-only query is planned and executed against an empty typed table with Apache DataFusion 45.2.0. We review the synthetic sample output separately. Check field types, thresholds, and counting rules against your own data. Read the testing methodology.

Query result

Net revenue retention by month

Expansion kept NRR above 100% in May and June, while declining GRR shows increasing contraction or churn underneath.

monthstarting_accountsstarting_mrr_usdending_mrr_usdnet_revenue_retention_pctgross_revenue_retention_pct
2026-05418126,400132,900105.1496.44
2026-06431132,900136,100102.4194.88
2026-07446136,100133,70098.2493.31

Synthetic example output. Run the query against your own event schema and thresholds before using it for operational decisions.

Net revenue retention by month: static chart of synthetic net_revenue_retention_pct values from the Calculate net and gross revenue retention example result
Download this SVG chart of the sample results for an article, runbook, or design review. Please credit Telemetry.

Reproduce the example

Download the sample data

The JSON bundle includes the event schema with field types, illustrative input rows, exact SQL, expected output, review notes, and engine version. The CSV contains the displayed result.

How the SQL works

  1. 1Only accounts with starting MRR enter the denominator, keeping new business outside retention.
  2. 2NRR compares total ending MRR with starting MRR and therefore includes expansion.
  3. 3GRR caps every account at its starting MRR, so expansion cannot offset contraction or churn.

Edge cases to check

  • Normalize annual, usage-based, and multi-currency contracts before taking snapshots.
  • Use one account hierarchy consistently when parent and child subscriptions can move independently.
  • Reconcile backdated billing corrections so historical snapshots do not drift silently.

Recommended dashboard

  • Trend: NRR and GRR by month
  • Bars: expansion, contraction, and churn MRR
  • Table: largest account-level revenue changes

Alert guidance

Review a complete month when GRR or NRR falls below its operating range; do not alert on an incomplete current-month snapshot.

Read alert setup

Set up the events this query needs

Related instrumentation and guides

Continue the analysis

Run it on your events

Create a table, adapt the fields, and save the result

Start free, send structured events, and use the query result as a chart, shared dashboard widget, or alert input.

Get an API key