Net Revenue Retention (NRR)
Net Revenue Retention (NRR): The percentage of revenue retained from existing customers over a period, including expansion, contraction and churn. Also known as Net Dollar Retention (NDR).
Also known as: NRR, NDR
Formula
NRR = MRR of cohort today / MRR of same cohort 12 months ago × 100NRR = (Beginning MRR + Expansion MRR - Contraction MRR - Churned MRR) / Beginning MRR × 100NRR-O = MRR of cohort today (organic only) / MRR of same cohort 12 months ago × 100NRR-M = MRR of cohort today (all expansion types and cohort reactivation) / MRR of same cohort 12 months ago × 100NRR-M = (Beginning MRR + All Expansion MRR + Cohort Reactivation MRR − Contraction MRR − Churned MRR) / Beginning MRR × 100NRR-M ≈ NRR-O + Reactivation + Cross-Module + New Buying Centre + Pricing Adjustment + Recontracting expansion Computable definition
The canonical formula in the GASP formula grammar. The MCP server compiles it to SQL over the datasets listed below.
(metric.mrr at period_start + metric.expansion_mrr - metric.contraction_mrr - metric.churned_mrr) / metric.mrr at period_start over cohort(field.customer_id, period_start) Unit: percent (the formula yields an unscaled ratio)
- Operating form (O) (see the dual-lens forms)
(metric.mrr at period_start + sum(field.mrr_change where field.event_type = 'expansion' and field.expansion_classification in ('same_product', 'usage_realisation')) - metric.contraction_mrr - metric.churned_mrr) / metric.mrr at period_start over cohort(field.customer_id, period_start)- Market form (M) (see the dual-lens forms)
(metric.mrr at period_start + sum(field.mrr_change where field.event_type in ('expansion', 'reactivation') and field.expansion_classification in ('same_product', 'new_module', 'new_buying_centre', 'pricing_adjustment', 'recontracting', 'usage_realisation')) - metric.contraction_mrr - metric.churned_mrr) / metric.mrr at period_start over cohort(field.customer_id, period_start)- Adjusted variant (see the adjusted variant)
(sum(field.mrr_start) + sum(field.mrr_change where field.event_type in ('expansion', 'contraction', 'churn') and field.change_nature = 'permanent')) / sum(field.mrr_start) over cohort(field.customer_id, period_start)
Breakdowns
by_segment: one row persegmentvalue
Notes: Period is trailing 12 months, over the customers active at period start (cohort method, the investor-comparable basis). NRR-O counts expansion tagged same_product or usage_realisation. NRR-M counts every expansion classification plus reactivation of cohort customers; customers who churned before the period and return are new business. The main formula is core.md's formula method. by_segment returns one row per customer segment, because retention differs most between SMB and enterprise; each snapshot and event counts in the segment it carries.
Data requirements
Grain: Customer cohort at period start · Frequency: Monthly · Aggregation: cohort (trailing 12 months) · Staged: yes, a cohort or prior-period comparison that a staged dataset makes cheaper · Main source: Billing.
| Field | Dataset | Type |
|---|---|---|
customer_id | customer | string |
customer_id | revenue_event | string |
customer_id | subscription | string |
customer_status | customer | string |
event_date | revenue_event | date |
event_type | revenue_event | string |
mrr | subscription | decimal |
mrr_change | revenue_event | decimal |
snapshot_date | customer | date |
snapshot_date | subscription | date |
subscription_status | subscription | string |
Example SQL (Postgres)
SELECT (CAST((((((SELECT COALESCE(SUM(mrr), 0) FROM subscription WHERE snapshot_date = :period_start AND subscription_status = 'active' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active'))) + ((SELECT COALESCE(SUM(mrr_change), 0) FROM revenue_event WHERE event_date >= :period_start AND event_date <= :period_end AND event_type = 'expansion' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active')))) - ((-(SELECT COALESCE(SUM(mrr_change), 0) FROM revenue_event WHERE event_date >= :period_start AND event_date <= :period_end AND event_type = 'contraction' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active'))))) - ((-(SELECT COALESCE(SUM(mrr_change), 0) FROM revenue_event WHERE event_date >= :period_start AND event_date <= :period_end AND event_type = 'churn' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active'))))) AS DOUBLE PRECISION) / NULLIF(((SELECT COALESCE(SUM(mrr), 0) FROM subscription WHERE snapshot_date = :period_start AND subscription_status = 'active' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active'))), 0)) AS nrr Access: recommended
sensitivity tier confidential,
access scope unscoped.
Guidance your policy engine enforces.
From an agent: with the GASP MCP server, call
lookup_metric({ "name": "Net Revenue Retention (NRR)" }) or generate_query({ "metric": "Net Revenue Retention (NRR)", "adapter": "<your adapter JSON>" }).
Benchmarks
- Below 90%: Leaky bucket. Growth requires constant new acquisition.
- 90-100%: Stable. You keep what you have.
- 100-110%: Good. Existing customers grow. (Median for VC-backed SaaS: 101-106%)
- 110-120%: Great. Strong expansion motion.
- 120%+: Exceptional. Top quartile performance.
What It Tells You
Whether the customers you had a year ago are paying you more or less today. Above 100%, the existing base grows on its own and new customers add on top; below it, new sales first have to replace what the base lost.
Common Mistakes
- Calculating over inconsistent time periods
- Including new customer revenue (that's not NRR)
- Excluding small customers or segments
- Confusing with Gross Revenue Retention (GRR)
Dual-Lens: Operating / Market Forms
Both governed forms are computed from the same Commercial Event Ledger, with Attribution Taxonomy Layer tags deciding which events each form counts.
Operating Form: Cohort NRR (NRR-O)
NRR-O uses the cohort method and includes only organic expansion: growth on the same product and usage realisation. It excludes expansion from new modules, new buying centres, reactivation, recontracting and pricing actions.
- CEL Source:
- `Revenue_Event`
- ATL Inclusion:
- - `lifecycle_attribution` ∈ (`retention`, `expansion`) - `expansion_classification` ∈ (`same_product`, `usage_realisation`) - Excludes: `expansion_classification` ∈ (`new_module`, `new_buying_centre`, `pricing_adjustment`, `recontracting`) and `lifecycle_attribution` = `reactivation`
NRR-O = MRR of cohort today (organic only) / MRR of same cohort 12 months ago × 100 What it tells you: Whether customers expand because the product gives them more value, with cross-sell, reactivation and pricing taken out. It is the closest NRR gets to a product-market fit signal.
Market Form: Account NRR (NRR-M)
NRR-M uses the cohort method over the customers active at period start, the same construction public SaaS companies report and investors benchmark (Bessemer, KeyBanc). It includes all six `expansion_classification` values plus reactivation of cohort customers. A customer who churned before the window and returns inside it is new business, not retention. A customer who churns and returns inside the window is in the cohort, so that reactivation counts.
- CEL Source:
- `Revenue_Event`
- ATL Inclusion:
- - All `expansion_classification` values included (`same_product`, `new_module`, `new_buying_centre`, `pricing_adjustment`, `recontracting`, `usage_realisation`) - `event_type` = `reactivation` included for customers in the period-start cohort - Excluded: `lifecycle_attribution` = `acquisition`; reactivation of customers who had already churned before period start (new business)
NRR-M = MRR of cohort today (all expansion types and cohort reactivation) / MRR of same cohort 12 months ago × 100 What it tells you: The total revenue retention and expansion picture that investors use for benchmarking and valuation.
Bridge
NRR-M ≈ NRR-O + Reactivation + Cross-Module + New Buying Centre + Pricing Adjustment + Recontracting expansion The delta (NRR-M − NRR-O) is the **Expansion Integrity Gap.** It shows how much of reported NRR comes from commercial motion (cross-sell, reactivation, pricing) rather than organic product expansion. A wide gap means NRR depends on sales execution more than product-led growth. That can be a sound strategy. The board should still know which one drives retention. SaaS Metrics Standards Board recommends the cohort method. Public SaaS companies report cohort-based NRR (NRR-M), so both forms use the cohort method and differ only in which expansion counts. ---
Adjusted Variant
This metric has an adjusted form that leaves out temporary revenue movements.
Tag CEL events with the change_nature field (permanent, temporary, scheduled_reversal)
and filter to permanent to compute Adjusted NRR.
That keeps permanent contraction, a risk signal, apart from expected reversals, which are neutral.
Related Metrics
Connected in the GASP relationship graph.
Upstream: what drives this
- Churned MRR component of NRR (Core)
- Contraction MRR component of NRR (Core)
- Expansion MRR component of NRR (Core)
- MRR component of NRR (Core)
Downstream: what this drives
- NRR measures Customer (Entity)
- NRR measures Subscription (Entity)