Net Revenue Retention is the metric that separates a SaaS business that grows because it keeps land-and-expanding within its existing base from one that's a leaky bucket refilled entirely by new sales. It's also one of the easiest metrics to compute inconsistently across two companies claiming the same number — the formula looks simple until you have to decide exactly which dollars go in which bucket.
The formula
NRR = (Starting MRR + Expansion − Contraction − Churn) / Starting MRR, measured over a cohort of customers that existed at the start of the period, with no new customers added to the numerator. It's a retention metric, not a growth metric — new logo revenue never enters the calculation at all.
WITH cohort AS (
-- customers active exactly 12 months ago
SELECT customer_id, mrr AS starting_mrr
FROM mrr_snapshots
WHERE snapshot_month = DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '12 months'
),
current_state AS (
SELECT c.customer_id, c.starting_mrr,
COALESCE(s.mrr, 0) AS current_mrr
FROM cohort c
LEFT JOIN mrr_snapshots s
ON s.customer_id = c.customer_id
AND s.snapshot_month = DATE_TRUNC('month', CURRENT_DATE)
)
SELECT
SUM(starting_mrr) AS starting_mrr,
SUM(current_mrr) AS ending_mrr,
ROUND(SUM(current_mrr) / NULLIF(SUM(starting_mrr), 0) * 100, 1) AS nrr_pct
FROM current_state;
Note the LEFT JOIN: a customer from the cohort who churned entirely contributes current_mrr = 0, not a missing row. Drop churned customers from the denominator instead of counting them at zero, and you'll compute a number that looks better than reality — this is the single most common NRR calculation bug I've seen in homegrown dashboards.
Why anything above 100% is the headline
NRR over 100% means your existing customer base would grow revenue even if you closed zero new logos next year — expansion (upsells, seat growth, upgrades) is outpacing contraction and churn within the same cohort. Public SaaS benchmarks put "good" NRR around 100-110% and "best-in-class" north of 120%, though the number that matters is the trend for your own business more than any external benchmark, since NRR is heavily influenced by pricing model (per-seat pricing naturally expands as customers grow headcount; flat-rate pricing doesn't).
A cohort can lose 15% of its customers to churn and still post 105% NRR, if the remaining 85% expanded enough to offset it. That's a legitimately healthy outcome for a company selling to growing accounts — but it means NRR alone can't tell you your logo churn rate. Track both.
Gross retention vs. net retention
Gross Revenue Retention (GRR) is the same formula but caps expansion at zero — it only measures how much revenue you'd have kept with no upsells at all: (Starting MRR − Contraction − Churn) / Starting MRR, and it can never exceed 100%. GRR isolates your churn and contraction problem from your expansion motion; NRR blends both together. A company with 85% GRR and 115% NRR has a real churn problem masked by a strong expansion motion — worth knowing before you conclude "retention is great" from NRR alone.
If NRR improved quarter over quarter, check whether that's from more expansion or less churn — they call for entirely different actions. Pulling GRR alongside NRR, even informally, tells you which half of the story changed.
Cohort-based calculation pitfalls
Beyond the churned-customer-as-zero mistake above, the other recurring error is mixing cohort vintages: computing NRR against "customers active at any point in the trailing 12 months" instead of a fixed point-in-time cohort inflates the number, because it excludes customers who churned early in the window from the denominator entirely. NRR should always be anchored to a specific starting snapshot date, with the same set of customer IDs tracked forward — no substitutions, no backfilling the cohort with customers who joined partway through.
Wrapping up
NRR is one formula, but the inputs — what counts as expansion, how churned accounts are handled in the denominator, which cohort snapshot you anchor to — are where the number actually gets made or inflated. Compute GRR alongside it so you know whether a shift in NRR came from expansion or from churn, and anchor every calculation to a fixed cohort rather than a rolling window.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.