What exactly is a Workload Unit?
Since April 2023, Bubble bills the use of its servers in Workload Units (WU): a measure of the work actually done, like fuel. The principle to remember fits in one sentence. Only server-side operations consume WU. Everything that happens in the user’s browser is free.
Free (in the browser): showing or hiding an element, setting a custom state, evaluating a condition client-side, navigating within a single-page application, running a front-end calculation.
Paid (on the server): a search (Do a search for), a write (Make changes, Create, Delete), scheduling or triggering a backend workflow, an external API call, a file upload, a page load.
A useful nuance: a free action becomes less free the moment you attach a condition that itself queries the server. A show/hide gated by a search pays for that search.
The goal isn’t zero WU. WU are fuel, meant to be spent; the point is to spend them wisely.
Where does a runaway bill come from?
Almost always from a handful of patterns, not from legitimate use. In a Bubble app, a 20/80 rule nearly always holds: 20% of workflows and searches consume 80% of the WU. The whole job is finding that 20%.
The culprits come up again and again: unfiltered searches that pull back whole lists, recursive workflows running away, data reloaded on a loop with every render. We break them down below, once we’ve settled the one thing to do before optimizing: measure.
Measure before optimizing
You don’t guess, you measure. Two tools, in this order.
App Metrics (Logs, App Metrics tab, Workload) gives you the 30-day overview: a per-day graph to spot spikes, a pie chart by activity type (searches, workflows, API calls, page loads), and detail down to the individual workflow. The method: find the spike days, identify the dominant activity type, drill into the detail, isolate the 3 to 5 biggest items, then cross-reference them with their frequency. A small cost that runs 10,000 times a day weighs more than a big one that runs once a week.
Server Logs gives you surgical precision: you trigger a workflow, read the WU cost action by action, fix, rerun, compare.
Two settings to check right away: the workload notifications (at 50, 75 and 100%) so you’re never caught off guard, and Infinite Recursion Protection (Settings, API). Apps created before July 2024 don’t have it on by default, and a single misconfigured recursive workflow can drain a monthly quota in under an hour.
The CVR framework: complexity, volume, repetition
Bubble offers a three-dimensional optimization framework, to apply in order of impact.
Complexity. Is there a fundamentally cheaper way to get the same result? A server search you could replace with a client-side filter on data already loaded? A condition you could evaluate in the browser instead of a server round-trip?
Volume. Are you returning more data than you need? Every character the server returns has a cost, tiny but cumulative. You tighten the search constraints, use :count or :sum instead of loading a whole list just to count it, and don’t load fields you aren’t displaying.
Repetition. Does the task run more often than it needs to? This is the most profitable dimension. Turning an “every time” into a “just once” can wipe out thousands of WU a day.
The costliest traps
Some patterns are worth naming, because you can’t see them in the editor.
The :filtered operator with an advanced constraint. The most dangerous of all. When the filter queries another data type, Bubble can fire one request per result row: a search filtered over 500 products triggers up to 501 requests on every render. The fix: store the filtered value as a field on the main type (denormalization), or put the constraint directly in the initial search.
Nested searches inside a Repeating Group. A group of N rows that runs one search per row executes N+1 requests on every load. The fix: pre-compute and store the value (the number of employees on the company record, say), or load the related list in a single request and do the matching client-side.
The runaway recursive workflow. A backend that schedules itself with no reliable stop condition can burn through an entire quota in minutes. Infinite Recursion Protection on, the stop condition as the very first step, testing on a limited data set before production.
Silent Database Triggers. A trigger fires on every change to a record of its type, and checks its condition each time, even when the answer is “no”. That check costs WU. On a type written to often (logs, sessions), the bill climbs fast. You consolidate, and ask whether the logic couldn’t live in the workflow that’s already making the change.
The development environment. Dev and Live share the same monthly quota. CSV imports and bulk tests in the development version consume WU before you’ve even launched.
Page loads. Every full load has a cost, page and searches included. A single-page architecture (show or hide groups rather than navigate to a new page) is fundamentally more frugal.
Optimize, buy more WU, or change plan?
Optimizing has a cost too: developer time. The Bubble bill has three independent levers: the plan, any add-on of pre-purchased WU, and overages. One thing that doesn’t change: WU pre-purchased through an add-on come out far cheaper than raw overages. The exact amounts change, so check the current pricing on bubble.io.
The decision rule comes down to three cases. You optimize when the overconsumption comes from bad patterns (nested searches, runaway triggers) rather than real usage: the development time pays for itself quickly. You buy an add-on when overages are regular but the app is simply growing, with no optimization bottleneck. You change plan when you need the features of a higher tier, or you’re consistently consuming above the included quota.
And avoid over-optimizing: a one-off spike (a launch import, a press mention, a data migration) is often cheaper to absorb than to engineer around. Optimization energy goes to the recurring, frequent items.
A Bubble app that costs too much? Let’s talk.