MongoDB Atlas backups: continuous bills 6.6x
Published · Updated · OhChimp Engineering

There is a BACKUP line on your MongoDB Atlas invoice, and if continuous cloud backup is switched on it is priced on a different schedule from the snapshots underneath it. The same 115 GB of backup data costs $16.10 a month as plain snapshots and $106.25 a month with continuous backup enabled.
Why continuous backup reprices every snapshot you keep
Atlas has two backup billing schedules, and a cluster is on one or the other.
Plain cloud backup bills snapshot storage at a flat per-GB-month rate that varies by provider and by region. On AWS that band runs $0.14 to $0.19. Google Cloud runs $0.08 to $0.12. Azure is the expensive one at $0.34 to $0.65, so an Azure cluster starts this exercise about two and a half times worse off than the same cluster on AWS.
Switch on continuous cloud backup, which is what buys you point-in-time restore, and Atlas stops using the flat rate for that cluster. It moves to a tiered schedule and applies it to the combined size of every snapshot plus the oplog. There are five tiers, and in AWS us-east-1 they run:
| Combined snapshot and oplog | Rate per GB-month |
|---|---|
| First 5 GB | Free |
| 5 GB to 100 GB | $1.00 |
| 100 GB to 250 GB | $0.75 |
| 250 GB to 500 GB | $0.50 |
| Over 500 GB | $0.25 |
Those figures are the bottom of each band. The tiered rate moves with provider and region the same way the flat rate does, and it spreads further: the 5 GB to 100 GB tier runs $1.00 to $1.55 on AWS, $0.60 to $0.95 on Google Cloud, and $1.00 to $3.95 on Azure. An Azure cluster can be paying nearly four times the rate this table shows.
Snapshot storage that billed at $0.14 now bills at $1.00.
MongoDB's own worked example does the arithmetic. A cluster in us-east-1 holding 115 GB of combined snapshot and oplog storage pays 95 GB at $1.00 plus 15 GB at $0.75, which comes to $106.25 a month. That same 115 GB on the flat snapshot rate is 115 times $0.14, or $16.10. You are paying 6.6 times as much for the same bytes.
That multiple belongs to 115 GB. It shrinks as the set grows, because the flat rate stays flat while the tiered one keeps stepping down. Walk the same us-east-1 schedule up: 250 GB bills $207.50 against $35.00 flat, a multiple of 5.9. At 500 GB it is $332.50 against $70.00, or 4.8. A terabyte comes to $457.50 against $140.00, which is 3.3. Size your own expectation from the tier your backup set actually sits in, because a large enough set pays closer to three times the flat rate than seven.
The free 5 GB sends small clusters the other way. Below roughly 5.8 GB of combined snapshot and oplog storage, continuous backup is the cheaper of the two schedules, because the free allowance covers more than the flat rate would have charged. The crossover is 5 divided by one minus your flat rate over your tier-one rate, so it is a property of your region rather than a constant. Every pairing of the published AWS and Google Cloud bands lands it between 5.4 and 6.3 GB, which makes 5.8 a fair planning number on either. Azure's two bands sit further apart and stretch it as far as 14 GB, so an Azure cluster can stay on the tiered schedule well past the size an AWS one should leave it. Past the crossover the gap widens to that 6.6 times peak around 115 GB, and then the higher tiers start closing it again.
Why the backup row appears every single day
Backup is quoted per GB-month and billed in GB days, which is why it shows up as a daily line item rather than a monthly one. The conversion is the monthly rate times 12, divided by 365.
At the $0.14 AWS rate that is $0.004603 per GB day. A 400 GB backup lands on your statement as 400 GB days at $0.004603, or $1.84 for that day, which is $55.20 across a 30-day month. Each backup retained on a given day contributes to that day's total. The same number arriving 30 times is 30 days of storage, billed a day at a time.
Deleting snapshots frees less than you expect
Atlas snapshots are incremental. After the first one, a new snapshot stores the blocks that changed since the most recent snapshot. What you are billed for is the unique data across the whole retained set.
MongoDB documents the consequence: when you delete a snapshot, data in it that also exists in any other snapshot is still counted as unique data. A block stops billing only once every snapshot referencing it is gone.
Atlas hands a dedicated cluster this default backup policy:
| Frequency | Snapshot taken | Retained |
|---|---|---|
| Hourly | Every 6 hours, or 12 on NVMe | 7 days |
| Daily | Every day | 7 days |
| Weekly | Every Saturday | 4 weeks |
| Monthly | Last day of the month | 12 months |
| Yearly | Every 1 December | 1 year |
Five schedules run at once, all firing at 18:00 UTC by default. Counting them is less useful than it looks, because when two policy items would produce the same snapshot Atlas keeps one and files it under whichever item has the longest retention. What you are left with is a short head and a very long tail.
The hourly snapshots are the most numerous, so they are what people delete first. They are also the cheapest, because six hours of change on a healthy cluster is a small delta.
The monthly schedule is the one sitting on your money. Twelve monthly snapshots reach back a year, and a block written thirteen months ago and deleted from the live collection since is still pinned by whichever monthlies reference it. Clear out every hourly and daily snapshot you own, and the monthly tail keeps that data billable.
Three more behaviours cost more than they look like they should.
Retention edits apply to future snapshots by default. Shorten monthly retention from 12 months to 3 and the nine snapshots already on disk keep their original expiry date. The Atlas CLI takes an explicit --updateSnapshots flag to apply new retention to snapshots that already exist. Skip it and your invoice will not move.
Cluster changes break incrementality. Atlas can retain more than one full snapshot per replica set, and the documented triggers include a failover, a change to the cluster tier, storage size or IOPS, a region priority change on a multi-region cluster, a topology change such as adding a shard, and cloud provider maintenance. Resizing a cluster down to save on compute forces a fresh full snapshot, so a right-sizing that trims your instance line can raise your backup line in the same billing period.
There is a ceiling, and it is the whole volume. Atlas can bill backup as high as the total storage capacity of the volume, depending on how the cloud provider stores the snapshots. A cluster that has lost incrementality several times over bills toward its disk size rather than a rounding error above its data size.
Find your backup share by hand
Everything below uses the Atlas Administration API v2 with an organization API key over HTTP digest auth. Atlas versions each endpoint separately and requires a versioned Accept header, so the version string changes from call to call. Send one Atlas does not recognise for that endpoint and you get a 406 rather than a helpful error.
Start with what backup actually costs you this month. The pending invoice is your live month-to-date bill:
export ATLAS_PUBLIC_KEY=... ATLAS_PRIVATE_KEY=...
ATLAS_ORG=<24-hex organization id>
curl -s -u "$ATLAS_PUBLIC_KEY:$ATLAS_PRIVATE_KEY" --digest \
-H "Accept: application/vnd.atlas.2023-01-01+json" \
"https://cloud.mongodb.com/api/atlas/v2/orgs/$ATLAS_ORG/invoices/pending" \
| jq '
[.lineItems[] | {
family: (if (.sku | test("BACKUP|SNAPSHOT|PIT")) then "backup" else "other" end),
cents: (.totalPriceCents // 0)
}]
| group_by(.family)
| map({family: .[0].family, dollars: ((map(.cents) | add) / 100)})'
Atlas SKUs read like ATLAS_AWS_INSTANCE_M30 and ATLAS_AWS_DATA_TRANSFER_SAME_REGION, so the family is the middle token and a substring match catches the backup rows. Each line item also carries quantity, unit, unitPriceDollars, tierLowerBound and tierUpperBound, which is how tiered backup pricing arrives split across several rows. Backup above about a third of the invoice is where this is worth your afternoon.
Next, find out which schedule the cluster is on:
ATLAS_GROUP=<24-hex project id>
CLUSTER=<cluster name>
curl -s -u "$ATLAS_PUBLIC_KEY:$ATLAS_PRIVATE_KEY" --digest \
-H "Accept: application/vnd.atlas.2024-08-05+json" \
"https://cloud.mongodb.com/api/atlas/v2/groups/$ATLAS_GROUP/clusters/$CLUSTER/backup/schedule" \
| jq '{
restoreWindowDays,
policies: [.policies[] | {
policyId: .id,
items: [.policyItems[] | {
id, frequencyType, frequencyInterval, retentionUnit, retentionValue
}]
}]
}'
Keep those policyId and item id values. The CLI needs both to change a retention rule, and there is no way to guess them.
Whether the cluster uses continuous backup is a property of the cluster itself rather than of its backup schedule, which is the detail that sends people round in circles. pitEnabled is readable on the schedule response and settable only on the cluster:
curl -s -u "$ATLAS_PUBLIC_KEY:$ATLAS_PRIVATE_KEY" --digest \
-H "Accept: application/vnd.atlas.2024-10-23+json" \
"https://cloud.mongodb.com/api/atlas/v2/groups/$ATLAS_GROUP/clusters/$CLUSTER" \
| jq '{name, pitEnabled, backupEnabled}'
Last, see where the gigabytes actually sit:
curl -s -u "$ATLAS_PUBLIC_KEY:$ATLAS_PRIVATE_KEY" --digest \
-H "Accept: application/vnd.atlas.2023-01-01+json" \
"https://cloud.mongodb.com/api/atlas/v2/groups/$ATLAS_GROUP/clusters/$CLUSTER/backup/snapshots?itemsPerPage=500" \
| jq -r '.results
| group_by(.frequencyType)
| map({
frequency: .[0].frequencyType,
count: length,
gb: ((map(.storageSizeBytes // 0) | add) / 1073741824 | floor)
})
| sort_by(-.gb)[]
| "\(.frequency)\t\(.count)\t\(.gb) GB"'
storageSizeBytes is the number of bytes taken to store that backup at the time of the snapshot. Those figures do not add up to your billed unique data, because a block shared by four snapshots is counted in all four here and billed once by Atlas. Read the ranking to see which frequency owns the tail.
Shorten the tail without giving up your recovery point
Decide the recovery point objective before you touch anything. Continuous backup buys restore to any second inside the restore window, and that window is capped by your hourly snapshot retention, which is 7 days on the default policy. If the honest answer to "how much data can we afford to lose" is "back to last night's daily snapshot", you are paying the tiered rate for a guarantee nobody asked for.
Turning it off moves the cluster back to the flat snapshot rate. It is a PATCH on the cluster, and the body is a partial update:
curl -s -u "$ATLAS_PUBLIC_KEY:$ATLAS_PRIVATE_KEY" --digest -X PATCH \
-H "Accept: application/vnd.atlas.2024-10-23+json" \
-H "Content-Type: application/json" \
"https://cloud.mongodb.com/api/atlas/v2/groups/$ATLAS_GROUP/clusters/$CLUSTER" \
-d '{"pitEnabled": false}'
Rollback is the same call with true, and Atlas starts a fresh oplog window from that moment. The restore window rebuilds going forward, so flipping it back does not hand you point-in-time coverage over the gap you just created. Run this on a cluster whose daily snapshots you have actually tested a restore from.
Then trim the retention tail that holds the gigabytes. The CLI wants the policy id, the policy item id, and the whole replacement rule:
atlas backups schedule update \
--clusterName "$CLUSTER" \
--projectId "$ATLAS_GROUP" \
--updateSnapshots \
--policy <policyId>,<policyItemId>,monthly,1,months,3
That trims monthly retention from twelve months to three. --updateSnapshots is the flag doing the work: it applies the new retention to the monthly snapshots already sitting on disk. Run the same command with --noUpdateSnapshots and you have changed a policy without changing a bill.
Rolling back a retention cut is where the asymmetry bites. Re-running the command with the original retentionValue restores the policy, and the snapshots the trim already expired do not come back. Change one frequency at a time, let a full billing day pass, and read the pending invoice again before you touch the next one.
Because billing follows unique data, your invoice responds to which snapshots are gone rather than how many. The count of snapshots you deleted tells you almost nothing about the saving.
A quick decision tree
graph TD
A[Backup SKUs over ~30% of the Atlas invoice] --> B{pitEnabled on the cluster?}
B -- No --> F[Trim the monthly and yearly tail]
B -- Yes --> C{"Snapshot plus oplog past the crossover? About 5.8 GB on AWS and Google Cloud"}
C -- No --> D[The free 5 GB wins. Leave continuous on]
C -- Yes --> E{Does the RPO need second-level restore?}
E -- Yes --> F
E -- No --> G[Set pitEnabled false, back to the flat rate]
F --> H{Retention change sent with --updateSnapshots?}
H -- No --> I[Existing snapshots keep their expiry. Bill will not move]
H -- Yes --> J[Re-read the pending invoice after a full billing day]
Related reading
The same shape turns up wherever a retention or tier decision is made once and then bills forever.
- S3 Standard-IA lifecycle rules is the same trade-off on object storage, where a minimum duration rather than unique data is what makes an early move cost you.
- Snowflake AUTO_SUSPEND covers the other managed-service default that bills for a capability you are not using.
Common questions
How much do MongoDB Atlas snapshot backups cost?
Plain cloud backup bills snapshot storage per GB-month at a rate set by your cloud provider and region: $0.14 to $0.19 on AWS, $0.08 to $0.12 on Google Cloud and $0.34 to $0.65 on Azure. MongoDB's own example is a 400 GB backup in an AWS region at $0.14, which comes to $56.00 a month. You pay for the unique data across every retained snapshot rather than for each snapshot in full, because snapshots after the first are incremental. Switching on continuous cloud backup replaces the flat rate with the tiered schedule above, which in AWS us-east-1 charges $1.00 per GB-month after the first free 5 GB.
Does turning off continuous cloud backup delete my snapshots?
No. Disabling pitEnabled stops the oplog capture that powers second-level restore and moves the cluster onto the flat snapshot rate. The snapshots already taken stay until their retention policy expires them, and scheduled snapshots keep running on the same policy. What you give up is restore to an arbitrary point in time between two snapshots.
Why did my Atlas backup bill go up after resizing a cluster?
Because a change to the cluster tier, storage size or IOPS is one of the documented triggers for Atlas keeping an extra full snapshot. Snapshots are normally incremental, so a full one adds the whole data size again rather than a delta. Failover, a multi-region priority change, adding a shard to the cluster and cloud provider maintenance do the same thing.
How far back can continuous cloud backup restore?
To any second inside the restore window, which is set by restoreWindowDays and cannot exceed the hourly snapshot retention time. The default policy retains hourly snapshots for 7 days, so 7 days is the default ceiling.
Does deleting one snapshot reduce my Atlas backup bill?
Only for blocks that no other retained snapshot references. Atlas counts data that also exists in another snapshot as unique data, so it keeps billing until every snapshot referencing it is gone. This is why deleting many hourly snapshots often moves the bill less than shortening one monthly retention rule.
Does the Atlas continuous backup rate keep climbing as the backup set grows?
No. The rate steps down through five tiers. In AWS us-east-1 the first 5 GB are free, the next 95 GB bill at $1.00 per GB-month, 100 GB to 250 GB bills at $0.75, 250 GB to 500 GB at $0.50, and everything above 500 GB at $0.25. The penalty against plain snapshot storage is therefore worst in the middle of the range. It peaks near 6.6 times around 115 GB and falls to about 3.3 times by a terabyte.
Why does the same backup charge appear on my invoice every day?
Backup is quoted per GB-month and billed in GB days. The rate is the monthly figure times 12, divided by 365, and every backup retained on a given day contributes to that day's GB days. The repeated rows are the billing unit rather than a duplicated charge.
How OhChimp approaches this
OhChimp connects with a read-only organization key and splits the real billed cents on your Atlas pending invoice by SKU family. Once snapshot and backup SKUs cross about a third of month-to-date spend, it raises the backup share. It ranks your clusters by what they actually billed, and flags dedicated clusters running without compute autoscaling so tier changes get planned rather than found on next month's backup line. Every finding shows up as a plan you read first, carrying a risk level and the steps to undo it, and nothing on your cluster moves until you press apply. OhChimp finds the backup spend on the invoice but cannot yet measure what one backup or tier change saves, so the saving on the plan stays an estimate.
The MongoDB Atlas integration page lists the read-only roles that organization key needs.