6 min read
Net new MRR: the five movements and how to read a bad month
New, expansion, reactivation, contraction and churn: the formula, why to compute it per customer day over day, a worked example, and how to read a bad month.
Net new MRR is how much your MRR changed over a period, split into the reasons it changed. If MRR was €6,200 on the first of the month and €6,439 at the end, net new MRR is €239. On its own that is a single number and not a very interesting one. The value is in the five movements underneath it, because a quiet €239 month and a chaotic €239 month look identical from the total.
What is the net new MRR formula?
net new MRR = new + expansion + reactivation − contraction − churn
Every change in MRR falls into exactly one of these five movements:
- New: a customer who has never paid you before starts paying.
- Expansion: an existing paying customer starts paying more. An upgrade, more seats, a move to a bigger plan, a coupon expiring.
- Reactivation: a former customer who had stopped paying comes back.
- Contraction: an existing paying customer pays less but doesn't leave. A downgrade, fewer seats, a new discount.
- Churn: a paying customer stops paying entirely.
Start-of-period MRR plus net new MRR always equals end-of-period MRR. If your own numbers don't satisfy that identity, something is being counted twice or not at all, and it's worth finding before you read anything else into them.
How do you classify each movement?
The cleanest way is to compute movements per customer, day over day. For each customer, take their total MRR yesterday and their total MRR today, and classify the difference.
function classify(before: number, after: number, hasPaidBefore: boolean) {
if (before === after) return null;
if (before === 0) return hasPaidBefore ? "reactivation" : "new";
if (after === 0) return "churn";
return after > before ? "expansion" : "contraction";
}
Then add up the amounts in each bucket across all customers and all days in the period.
Two choices in there matter more than they look.
Why per customer and not per subscription?
Because customers do things with subscriptions that aren't really churn or growth. Someone switches from your monthly plan to the annual plan, and your billing system cancels one subscription and creates another. Counted per subscription, that is a churn and a new customer on the same day. Counted per customer, it is the difference between the two, usually a small contraction because annual plans are discounted.
The same goes for a customer who pays on the web and in your app. If you add their subscriptions together under one customer, cancelling the app plan while keeping the web plan is contraction, not churn. That only works if you can match the two subscriptions to one person, which is covered in combined MRR for Stripe and RevenueCat.
Why day over day and not month end to month end?
Because a monthly snapshot loses anything that starts and ends inside the month. A customer who signs up on the 3rd and cancels on the 25th never appears in either snapshot, so they show up as nothing. In a day-over-day computation, they are €29 of new MRR and €29 of churn. The net is the same, but you now know that you acquired someone and lost them in three weeks, which is a fact worth having.
It also keeps upgrade-then-downgrade visible. A customer who tries the bigger plan for ten days and goes back shows up as both expansion and contraction instead of disappearing.
A worked example
Say a small SaaS starts October at €6,200 MRR. Here is what happened, customer by customer, grouped by movement:
| Movement | What happened | MRR |
|---|---|---|
| New | 14 new customers: 12 on €29, 2 on €79 | +€506 |
| Expansion | 4 upgrades, 2 coupons ending | +€180 |
| Reactivation | 2 former customers came back | +€58 |
| Contraction | 3 downgrades, 1 switch to annual | −€95 |
| Churn | 9 cancellations, 3 of them after failed payments | −€410 |
| Net new MRR | +€239 |
End-of-month MRR is €6,200 + €239 = €6,439.
Read the table row by row and it says more than the total. New MRR is healthy. Churn is large: €410 out of a starting €6,200 is 6.6% of revenue lost to cancellations, before contraction. And a third of the cancellations came from failed payments, which is a billing problem, not a product one. Two of the expansion movements are coupons ending, so real upsell was smaller than the €180 suggests.
A founder looking at only "+€239" would call it a fine month. A founder looking at the table would spend the next week on failed-payment emails.
How should you read a bad month?
Say net new MRR comes out at −€150. Don't start with the total. Start with the five movements and ask which one moved compared with your usual month.
If new MRR fell, the problem is at the top. Look at trials started, trial-to-paid conversion and where signups came from. A post that used to bring customers may have dropped in search, or a campaign ended. Revenue by landing page and channel tells you where the gap is; which blog posts bring paying customers covers how to measure that.
If churn rose, check who left. One large customer leaving is a conversation to have with that customer. Many small ones leaving from the same signup month or the same plan is a pattern. Separate voluntary cancellations from involuntary ones caused by failed payments; they have different fixes. How to calculate churn rate goes through the splits that help.
If contraction rose, look at plan changes. A pricing change, a new cheaper tier or a seat-based plan where teams are shrinking usually shows up here first.
If expansion fell, check whether last month's expansion was inflated by coupons ending. A big launch discount expiring produces a one-off wave of expansion, and the month after looks like a drop.
If nothing stands out, look at currency. If you report in euros and bill some customers in dollars, a renewal at a different exchange rate changes their MRR slightly with no change in plan. That can show up as a scattering of small expansion and contraction amounts. It's real in your reporting currency, but it isn't customer behavior.
Then check the count behind each movement. A month with one big churn and a month with twelve small ones can have the same churn MRR. The first is usually noise. The second usually isn't.
A note on small numbers
At a few thousand euros of MRR, a single customer can swing any movement. That doesn't make the breakdown useless; it makes the per-customer detail more important. When net new MRR is driven by three customers, you can name them, and naming them is more useful than any rate.
Joinsight computes the five movements per customer, day over day, from Stripe and RevenueCat, and when MRR moves sharply, an alert explains the cause, computed by code from those movements. The rules are on the metric definitions page.