Forum Discussion
OneLake storage keeps growing?
Context
We are running a medallion architecture in Microsoft Fabric (Bronze → Silver → Gold) sourced from JD Edwards (sql database) via a nightly pipeline. All three layers use mode("overwrite") with overwriteSchema=True. We have roughly 15 Delta tables per layer, so approximately 45 tables being fully overwritten every night.
Problem
Our OneLake storage is growing steadily — currently at 47.08 GB current and 42.61 GB billable. In the Fabric Capacity Metrics app, the daily storage bar fluctuates but billable storage climbs in a straight line with no sign of levelling off. When we inspect individual Delta table files, none of them are particularly large.
We checked the size with the following notebook:
def folder_size_mb(path):
try:
total = 0
for f in mssparkutils.fs.ls(path):
total += folder_size_mb(f.path) if f.isDir else f.size
return total
except:
return 0
for layer in ["LH_Bronze", "LH_Silver", "LH_Gold"]:
base = f"..."
files_mb = folder_size_mb(f"{base}/Files") / 1e6
tables_mb = folder_size_mb(f"{base}/Tables") / 1e6
print(f"{layer:12} Files/: {files_mb:8.0f} MB Tables/: {tables_mb:8.0f} MB")
LH_Bronze Files/: 547 MB Tables/: 1974 MB
LH_Silver Files/: 0 MB Tables/: 2171 MB
LH_Gold Files/: 0 MB Tables/: 1782 MB
And the metrics apps shows:
What we have tried
Early in the project our Bronze pipeline ran hourly on append mode, which caused storage to explode. After switching to overwrite and waiting 7 days, storage dropped. We are now on a nightly schedule. We ran VACUUM table RETAIN 0 hours but did not observe a meaningful reduction.
Question
Are we doing something wrong or forgetting something? And how can we reduce the storage as shown in the app?
Hi Questions_D2i,
You’ve actually already done most of the correct technical checks (VACUUM, OPTIMIZE, even validating file-level size), so your conclusion is very close to reality, this is not a Delta issue anymore, it’s a OneLake retention + metrics interpretation gap.
Let me clarify what’s really happening:
1. Your math is correct -nd that’s the key signal
The fact that:
- ~6 GB real data/day
- ~60 GB shown in Metrics
- ~7 days difference
…strongly indicates that deleted/overwritten files are still sitting in OneLake soft-delete retention window, even though Delta has already removed them logically.
So yes -VACUUM is working, but it is only cleaning Delta-visible files, not what the Capacity Metrics app still counts during retention.
2. Why storage doesn’t drop immediately
Even after:
- VACUUM RETAIN 0
- OPTIMIZE
- overwrite mode
Fabric still keeps data due to:
- OneLake soft-delete / recovery retention layer
- Capacity Metrics reporting billable retained storage over time window, not just live Delta state
That’s why you see a flat + increasing trend even after cleanup jobs run correctly.
3. Important clarification about Item Recovery / Recycle Bin
What you’re looking for is a bit misleading in Fabric today:
- There is no classic “Recycle Bin UI” per workspace for OneLake files
- “Item recovery” setting does not directly expose a manual purge UI for Delta files
- Most of this cleanup is system-managed during retention expiry (~7 days by default)
So you won’t find a button or notebook API to immediately clear that gap.
4. What you should NOT do
- Disabling workspace retention blindly ❌ (not recommended and unrelated to Delta file retention behavior)
- Trying to manually “force delete” OneLake system-managed retained files ❌
These won’t solve the billing gap and can create unintended data recovery issues.
5. What actually works (real resolution path)
You basically have 3 valid options:
Option A — Wait for retention window to expire (expected behavior)
After ~7 days, you should see:
- Metrics curve flatten
- Billable storage stabilize
This is the most common confirmation test.
Option B :- Reduce overwrite footprint (best long-term fix)
Instead of full overwrite daily:
- Move to incremental / partition-level updates
- This drastically reduces “orphan delta churn”
Option C- Controlled compaction strategy
Keep:
- nightly OPTIMIZE
- scheduled VACUUM (fine tuned retention, not always 0)
- plus monitoring of file churn per table
Final takeaway
Nothing looks “wrong” in your implementation.
What you are seeing is basically:
Delta cleanup already done + OneLake retention still holding physical data + Metrics showing retention based billing lag
So the gap between “real storage” and “metrics storage” is expected in this window.
Regards!
Datta Sable
11 Replies
- arabalcaSuper User
Hi Questions_D2i ,
Two things are happening at the same time.
1. What the Capacity Metrics App is showing
The second image you shared displays the 30 days ago accumulation, not the current size of OneLake at a given point in time. This means that even if you reduced your storage to zero today, the line would still be growing — because it reflects the cumulative sum of GB since the 1st of the month. This is the expected behavior of Fabric's billing model, not an issue with your data. (https://learn.microsoft.com/es-es/fabric/enterprise/metrics-app-storage-page#column-charts
)
2. The actual problem: Delta orphan files
With overwrite across 45 tables every night, Delta Lake does not physically delete the previous Parquet files — it marks them as removed in the _delta_log but they remain in OneLake. Those orphan files increase the real daily size, and that larger daily size is what feeds the monthly accumulation.
3. Solution: OPTIMIZE + VACUUM across all three layers every night
OPTIMIZE → compacts the multiple small Parquet files generated by each overwrite into larger files, reducing fragmentation and total size
VACUUM → physically deletes the orphan files that Delta has marked as removed
Always run OPTIMIZE before VACUUM, as OPTIMIZE itself generates new orphan files that VACUUM will clean up in the same pass.
More:
- Official documentation:
VACUUM in Fabric: https://learn.microsoft.com/fabric/data-engineering/lakehouse-table-maintenanceIf you find this helpful please give it a 👍, and if it answered your question please mark it as a solution ✅. This helps the community and motivates me to keep contributing. Thank you!
- oussamahaimoudMemorable Member
Hi Questions_D2i,
Hope you're doing well!
Root cause
Even with mode("overwrite"), Delta Lake never deletes old files immediately. It marks them as "deleted" in the transaction log while new Parquet files are written alongside the old ones, until explicitly cleaned up.
Your nightly pipeline stacks one full copy every night. Your 47 GB = 8 nightly copies of your 6 GB actual dataset.
Why VACUUM didn't work ?
1. The safety check blocked it silently Without disabling retentionDurationCheck, VACUUM silently falls back to the 7-day default.
2. OneLake's soft-delete layer retains files for up to 7 days even after Delta removes them logically.
One-time cleanup
pythonfrom delta.tables import DeltaTable layers = { "LH_Bronze": "abfss://...<Bronze path>...", "LH_Silver": "abfss://...<Silver path>...", "LH_Gold": "abfss://...<Gold path>..." } spark.conf.set("spark.databricks.delta.retentionDurationCheck.enabled", "False") for layer, base_path in layers.items(): for table in mssparkutils.fs.ls(f"{base_path}/Tables"): try: dt = DeltaTable.forPath(spark, table.path) dt.optimize().executeCompaction() dt.vacuum(0) print(f"✅ {layer} / {table.name}") except Exception as e: print(f"❌ {e}") spark.conf.set("spark.databricks.delta.retentionDurationCheck.enabled", "True")
Safe here since full overwrites don't require time-travel history. See VACUUM docs.
Prevent recurrence by adding to every nightly pipeline
pythonspark.conf.set("spark.databricks.delta.retentionDurationCheck.enabled", "False") for layer_path in [bronze_path, silver_path, gold_path]: for table in mssparkutils.fs.ls(f"{layer_path}/Tables"): dt = DeltaTable.forPath(spark, table.path) dt.optimize().executeCompaction() dt.vacuum(0) spark.conf.set("spark.databricks.delta.retentionDurationCheck.enabled", "True")
Or permanently via Delta table properties:
pythonspark.sql(""" ALTER TABLE my_table SET TBLPROPERTIES ( 'delta.logRetentionDuration' = 'interval 1 days', 'delta.deletedFileRetentionDuration' = 'interval 0 hours' )""")
Expected results
Layer Now After FixBronze + Silver + Gold ~47 GB ~6–7 GB Billable storage flattens within 24–48h after OneLake's soft-delete window clears. Your architecture is correct. So, this is purely a Delta housekeeping gap.
Hope this helps. Feel free to ask me questions if needed, and don’t forget to give kudos & Accept as Solution if this guidance worked for you. That's motivate me to keep helping.
Best regards,
Oussama (Data Consultant & Fabric's Expert)
- Questions_D2iNew MemberThanks for all the suggestions. We already had VACUUM RETAIN 0 HOURS running daily with spark.databricks.delta.retentionDurationCheck.enabled = false, and we've now also added optimize().executeCompaction() before vacuum. Still no reduction in storage according to the Capacity Metrics app after a few days. It's even still increasing:We did a deeper investigation and found that mssparkutils.fs.ls() (recursively measuring all files & tables in our three lakehouses) shows only ~6 GB of actual live files. The Metrics app shows ~60 GB. The ~54 GB difference matches almost exactly 7 days × ~6 GB daily overwrite — which strongly suggests the gap is explained by OneLake's soft-delete layer retaining files for ~7 days after Delta/VACUUM has logically deleted them.So VACUUM is working correctly at the Delta level, but possibly the physically deleted files are being held in OneLake's soft-delete state and still counted in the Metrics app.Based on stoic-harsh's answer, the fix should be in the Fabric Admin Portal to reduce the OneLake soft-delete retention.However, fabric item recovery is completely disabled:The only enabled retention period is for the workspace:Should we disable this one? I feel like this would make no sense, since we're not deleting any workspace. Furthermore, I can't find the 'recycle bin' in the UI: is there any way to access or empty that in a notebook? Or is it disabled because we don't have the item recovery enabled?If anyone could point us to another direction or knows something we can still try that would be amazing, really appreciate the help!
- sabledattatrayAdvocate II
Hi Questions_D2i,
You’ve actually already done most of the correct technical checks (VACUUM, OPTIMIZE, even validating file-level size), so your conclusion is very close to reality, this is not a Delta issue anymore, it’s a OneLake retention + metrics interpretation gap.
Let me clarify what’s really happening:
1. Your math is correct -nd that’s the key signal
The fact that:
- ~6 GB real data/day
- ~60 GB shown in Metrics
- ~7 days difference
…strongly indicates that deleted/overwritten files are still sitting in OneLake soft-delete retention window, even though Delta has already removed them logically.
So yes -VACUUM is working, but it is only cleaning Delta-visible files, not what the Capacity Metrics app still counts during retention.
2. Why storage doesn’t drop immediately
Even after:
- VACUUM RETAIN 0
- OPTIMIZE
- overwrite mode
Fabric still keeps data due to:
- OneLake soft-delete / recovery retention layer
- Capacity Metrics reporting billable retained storage over time window, not just live Delta state
That’s why you see a flat + increasing trend even after cleanup jobs run correctly.
3. Important clarification about Item Recovery / Recycle Bin
What you’re looking for is a bit misleading in Fabric today:
- There is no classic “Recycle Bin UI” per workspace for OneLake files
- “Item recovery” setting does not directly expose a manual purge UI for Delta files
- Most of this cleanup is system-managed during retention expiry (~7 days by default)
So you won’t find a button or notebook API to immediately clear that gap.
4. What you should NOT do
- Disabling workspace retention blindly ❌ (not recommended and unrelated to Delta file retention behavior)
- Trying to manually “force delete” OneLake system-managed retained files ❌
These won’t solve the billing gap and can create unintended data recovery issues.
5. What actually works (real resolution path)
You basically have 3 valid options:
Option A — Wait for retention window to expire (expected behavior)
After ~7 days, you should see:
- Metrics curve flatten
- Billable storage stabilize
This is the most common confirmation test.
Option B :- Reduce overwrite footprint (best long-term fix)
Instead of full overwrite daily:
- Move to incremental / partition-level updates
- This drastically reduces “orphan delta churn”
Option C- Controlled compaction strategy
Keep:
- nightly OPTIMIZE
- scheduled VACUUM (fine tuned retention, not always 0)
- plus monitoring of file churn per table
Final takeaway
Nothing looks “wrong” in your implementation.
What you are seeing is basically:
Delta cleanup already done + OneLake retention still holding physical data + Metrics showing retention based billing lag
So the gap between “real storage” and “metrics storage” is expected in this window.
Regards!
Datta Sable - stoic-harshSuper User
Hey Questions_D2i,
You are already running the VACCUUM command with 0 hours retention, which is right.
Also agree with oussamahaimoud on the soft-delete concept. This Microsoft doc explains the topic in bit more detail: https://learn.microsoft.com/en-us/fabric/onelake/onelake-disaster-recovery
]
And this doc covers the billing: https://learn.microsoft.com/en-us/fabric/admin/retention-recovery
To resolve, notebook scripts or API Calls is one of the ways to identify soft-deleted items and remove them. However, my preferred way is to control the retention (extend or permanently disable) directly from the Admin Portal UI:
Additionally, I can view or permanently remove these soft-deleted items through the Recycle Bin UI:
Hope this helps!
Best,
Harshit
- Questions_D2iNew Member
Hey stoic-harsh,
Thanks for your additional input and links to the documentation!
I was wondering where you see the Recycle Bin, i cannot seem to find it 😅- stoic-harshSuper User
Hey Questions_D2i,
No worries😄. A Tenant Admin has to enable this setting (covered in previous reply): Admin Portal > Tenant Settings > Item Recovery (toggle on) and click Apply.
Once enabled, the Recycle Bin appears in your workspace. Permission model:
- Contributors and above can restore items.
- Only Admins can permanently delete from the bin.
Best,
Harshit
- rizalard0684Resolver III
Hi Questions_D2i Let me summarise the answers above (correctly said) in a more succinct way:
- Overwrite does not mean (immediately) hard delete
Delta table does NOT delete old files immediately, it marks them as removed (i.e. soft delete), but keeps them physically for history (by default 7 days retention).
https://www.mssqltips.com/sqlservertip/8201/microsoft-fabric-optimize-delta-tables/ - VACUUM didn’t work (this is expected)
Running VACUUM retain 0 hours won't work unless the safety is disabled.
SET spark.databricks.delta.retentionDurationCheck.enabled = false; VACUUM table_name RETAIN 1 HOURS;- Reduce overwrite pattern (better for long-term)
Instead of full overwrite, why don't you use incremental loads with CDC / watermark / date partition and only update changed data
In summary, Delta keeps history, overwrite creates new version and storage grows until retention cleanup kicks in. My suggestion is:
- Run forced VACUUM to clean backlog (as an adhoc solution)
- Decide to accept 7-day retention storage OR shorten the retention (safely)
- Move from full overwrite to incremental load
- Overwrite does not mean (immediately) hard delete
- v-pnaroju-msftCommunity Support
Thankyou, arabalca, oussamahaimoud, stoic-harsh, and rizalard0684 for your responses.
Hi Questions_D2i,
We appreciate your inquiry through the Microsoft Fabric Community Forum.
We would like to inquire whether have you got the chance to check the solutions provided by arabalca, oussamahaimoud, stoic-harsh and rizalard0684 to resolve the issue. We hope the information provided helps to clear the query. Should you have any further queries, kindly feel free to contact the Microsoft Fabric community.
Thank you. - sabledattatrayAdvocate II
Hi Questions_D2i,
This is a very common issue when managing a Medallion Architecture in Microsoft Fabric! The steady storage growth you are experiencing in your Bronze, Silver, and Gold layers is because Delta tables in Fabric retain all historical parquet files from previous writes to support Delta Time Travel, even when using mode(overwrite).
Since a full overwrite creates a new Delta table version every night while keeping the old ones, the historical data files accumulate in OneLake until they are cleaned up.
Here is how you can optimize and resolve this across your Medallion layers:
- Bronze (Ingestion layer): Since Bronze gets full night-by-night overwrites from JD Edwards, time travel is rarely needed here. You can safely run VACUUM on Bronze tables with a low retention window (e.g. RETAIN 0 HOURS if zero time-travel is needed) to immediately reclaim storage.
- Silver & Gold (Transformation layers): For Silver and Gold, you might want to retain a few days of history for debugging. Run VACUUM with RETAIN 72 HOURS or RETAIN 168 HOURS (7 days) at the end of your nightly pipeline to keep only the necessary history and automatically purge everything else.
- Nightly Pipeline Cleanup Notebook: Create a simple utility notebook that loops through the tables in your Bronze, Silver, and Gold lakehouses to execute the VACUUM command, and trigger it as the final stage of your orchestrator pipeline.
For a complete architectural guide on best practices for structuring, partitioning, and managing OneLake storage across your Medallion layers, feel free to check out this comprehensive blueprint: dattasable.com/blog/microsoft-fabric-medallion-architecture-guide
Hope this helps get your storage costs under control! If this solves your issue, please consider marking this reply as the Accepted Solution so others in the community can find it.Regards,
Datta Sable - v-pnaroju-msftCommunity Support
Hi Questions_D2i,
We are following up to see if what we shared solved your issue. If you need more support, please reach out to the Microsoft Fabric community.
Thank you.