DEV Community

CostFabric
CostFabric

Posted on Originally published at costfabric.com

Why Pausing Your Microsoft Fabric Capacity Triggers Surprise Azure Bills (Smoothing & Carryforward)

Originally published at costfabric.com.

A lot of data teams move to Microsoft Fabric on a Pay-As-You-Go F-SKU (F16, F32, or F64) with a simple cost-saving plan: run the capacity during business hours, pause it at 7:00 PM via an Azure Automation runbook or Logic App, and cut the monthly bill in half.

Then the first month's Azure invoice arrives, and the savings are nowhere near 50%. Even worse, you see unexpected billing spikes right at the exact minute the capacity was paused.

If you have seen this happen, you are running into how Microsoft Fabric handles 24-hour background smoothing and carryforward settlement on pause.

How Fabric smoothing actually works under the hood

In Microsoft Fabric, your capacity does not bill you per query. It gives you a fixed pool of Capacity Units (CUs) every second:

  • An F16 gives you 16 CU-seconds per second (57,600 CU-seconds per hour).
  • An F32 gives you 32 CU-seconds per second (115,200 CU-seconds per hour).
  • An F64 gives you 64 CU-seconds per second (230,400 CU-seconds per hour).

To keep short spikes from immediately throttling your users, Fabric smooths compute usage over time. Interactive operations (like opening a Power BI report or running a DAX query) are smoothed across a minimum of 5 minutes. Background operations (like scheduled semantic model refreshes, Dataflow Gen2 runs, Spark notebooks, and Data Factory pipelines) are smoothed across a full 24-hour window.

When a heavy nightly refresh or Dataflow Gen2 batch consumes more CUs than your SKU provides in that window, Fabric borrows capacity from future windows over the next 24 hours. That borrowed usage is called carryforward.

What happens when you pause a capacity with active carryforward

As long as your capacity stays running 24/7, that 24-hour smoothing window works in your favor. A massive 6:00 AM refresh spreads its CU footprint gently across the rest of the day and night while the capacity sits mostly idle.

When you pause a Pay-As-You-Go capacity in Azure, however, the 24-hour clock stops immediately. Microsoft does not forgive whatever smoothed CU debt was still sitting in your future carryforward queue. Instead, when the capacity transitions to Paused, Azure settles all remaining accumulated carryforward and smoothed CU usage onto your bill at once.

Consider a concrete example on an F32 capacity (32 CUs):

  1. At 4:30 PM, a set of heavy Dataflow Gen2 jobs and semantic model refreshes kick off.
  2. Together they consume 460,800 CU-seconds of work. On an F32, that equals 4 full hours of 100% capacity compute, which Fabric normally spreads out at roughly 16.7% CU across the next 24 hours.
  3. At 6:30 PM, your automation script pauses the F32 capacity to save money overnight.
  4. Only 2 hours of that 24-hour smoothing window have elapsed. The remaining unabsorbed CU debt is immediately flushed and billed as an overage charge when the capacity pauses.

Even worse, if teams pack all of their refreshes right before the evening pause window or right after the morning resume window, they end up paying for the daytime active hours plus the settled carryforward from the background jobs. At that point, a paused Pay-As-You-Go capacity can easily cost more than a 1-year Azure Reservation running 24/7 (since a 1-year reservation already discounts the hourly rate by roughly 40.5%, putting the break-even point around 99.2 hours per week).

How to check if your capacity is carrying hidden smoothing debt

Before you build pause/resume automation or change your F-SKU size, look at a 14-day export from the Microsoft Fabric Capacity Metrics app and check three numbers:

  1. Your baseline background CU % floor at 3:00 AM. If nobody is querying reports at 3:00 AM and no jobs are running, yet your capacity sits at 25% to 45% CU utilization, that entire floor is 24-hour smoothed background work from earlier in the day.
  2. The timing of your heaviest background jobs relative to your planned pause hour. Any heavy background job that finishes within 6 to 12 hours before a pause will leave a large chunk of smoothed CUs unsettled when the shutdown hits.
  3. Total weekly active hours plus carryforward drain time. Once you add the hours required to let background debt drain cleanly before pausing, many teams discover their true billable window is 110+ hours per week.

We put together a lightweight, zero-macro Excel workbook and a 60-line Python CSV script that calculate your idle CU hours, your 24-hour background smoothing floor, and your unutilized spend percentage from a standard Capacity Metrics export. You can grab the free offline checker at https://costfabric.com/tools/.

Diagnosing the bleed is step one. Actually fixing it without breaking morning report SLAs requires isolating the specific artifacts driving the smoothing floor, deciding whether to split bursty ETL onto a separate capacity or switch billing models, and scheduling your workload windows so carryforward hits zero before shutdown. If you want an engineer-reviewed breakdown of your own tenant's metrics, you can request a free 48-hour capacity readout at https://costfabric.com/check/.

Top comments (1)

Collapse
 
karanpulyala profile image
Karan Pulyala •

The 3:00 AM background floor is a really practical way to spot this without digging through the whole metrics app. One option worth adding to the "fix" side for teams whose floor is mostly Spark: Fabric's Autoscale Billing for Spark moves notebooks and Spark job definitions off the shared capacity and bills them pay-as-you-go, so their CU usage isn't smoothed into the capacity at all and there's nothing left to settle at pause time for that work. It doesn't help with semantic model refreshes or Dataflow Gen2, but it can make the remaining smoothing debt small enough that a nightly pause works the way people expect. On the scheduling side, moving heavy refreshes to just after the morning resume rather than just before the evening pause gives each job most of the day to burn down before the next shutdown.