Bubble is infinitely flexible – there's an endless list of apps you can build and an endless number of ways in which you can realize your vision. Finding the right way for your specific use case can have a big impact on how many workload units (WU) your app needs (and therefore which of Bubble’s pricing plans might be right for you).
In our webinar, “Building Efficiently on Bubble,” our team explored how to measure, optimize, and diagnose your own workload usage. You can replay the event below and, for a deeper dive into this new metric, keep reading on.
In this article, we’ll help you optimize your workload so you can make your app leaner and more efficient and get the most bang for your buck. We’ll cover three things:
- What drives workload consumption
- How to understand your app’s current workload
- Some common practices that might drive workload up, and alternative ways to build more efficiently
One quick note before we dive in: There’s no textbook definition for the best way to build your app. Every app is different. However you choose to get there, more efficiency means better performance for your app and your users. In the next few sections, we’ll help you optimize your own workload usage, wherever you see fit.
What drives workload usage up?
Workload, by definition, measures the work that Bubble does to power your app. In other words, this is Bubble’s way of quantifying all the underlying activities your app does as it runs.
We’ll explore some specific examples further down, but the bottom line is this: make sure your app only does the work it needs to do, when it needs to do it.
So that means the biggest contributor to inefficient workload usage is unnecessary activity done by your app. Often, this can be a regular behavior your app performs more frequently than it needs to. Or it could be an action that interacts with a lot more data than required. (If you’ve done any work to optimize your app’s performance in the past, most of what you learned during that process will apply here, too.)
Either way, the first step is finding a good place to start. And to do that, you’ll want to get a better view at your current workload usage.
How do I understand what’s driving my app’s current workload?
Bubble has a set of charts to help you understand your workload usage and identify its biggest drivers. Within your app, visit the Logs tab, then look under App metrics.
The bar graph shows an aggregate measure of how much work your app has done over a period of time, and the pie chart gives you a detailed breakdown of the different areas contributing to your overall workload. You can also drill down into a particular category by clicking on it.
For example, in the pie chart above, this app had 80% of its workload created by a single recursive workflow (more on these in a second). That could be really helpful information as you decide where to focus first.
Check out our interactive walk-through of the App Metrics dashboard below to learn more.
Some common workload inefficiencies you might uncover
Here are a few common pitfalls to keep an eye out for as you look into improving your workload usage. (To dive deeper, check out this section of the Bubble manual.)
Excessive database activities (fetching or creating data)
There are infinite reasons why you may need to find data in your database and reference the results of that search on your page. But inefficient database searches are a common driver of unnecessary workload, especially when you’re searching a massive volume of data or performing multiple searches in quick succession.
Take another look anywhere your app searches the database and ask yourself:
- “Can I add any additional constraints to this search?” Constraints can help lower the volume of data your search has to sift through, decreasing the workload of the action. And in most cases, added constraints are even more efficient than advanced filtering. (Pro tip: If you need to use the “Advanced…” option inside the “:filtered” operator, we recommend using it on top of other search constraints that help narrow down the search. By itself, advanced filtering loads a lot of data as part of the process.)
- “Can I cut down on how many database searches I’m performing?” Even if they’re part of the same process, each search will impact workload. See if you can remove or constrain subsequent searches. (Don’t forget you can also reference the results of a single search elsewhere in your app through custom states or — when working in a workflow — using the “result of step x…” operator.)
- “Am I running any recurring database searches in the background?” If you’re performing a database search when you don’t actively need the results, there’s a good chance you’re probably using some workload inefficiently. The more strategically you can time your searches or data references, the better.
This holds true for logging new data as well. For example:
- Let’s say our app creates a “page loaded” entry in the database whenever a page is loaded. That information could be useful, but this process quickly bloats the database and uses up a high amount of workload.
Recurring or scheduled workflows
You may have a workflow on a page set to trigger multiple times. Just make sure it isn’t triggering more often than you really need. For example:
- Let’s say we have a page workflow that “does X every X seconds.” That may be the right choice for client-side actions (like scrolling through a slideshow), but it will probably use an unnecessary amount of workload when you’re updating or checking for changes in data.
- The fix: If you need to watch data for changes then and perform a workflow as a result, consider using a backend database trigger instead.
Meanwhile, on the backend of your app, a recursive workflow can reschedule itself — a powerful driver of workload, for better or worse. Some apps use recursive workflows unnecessarily, while others could actually use one to make a process more efficient.
Look out for:
- Recursive workflows that reschedule themselves when a certain condition is met or unmet. If they aren’t carefully configured, conditionals can cause unnecessary triggers. If, say, a backend workflow reschedules itself when a search is not empty, that could lead to an infinite loop.
- Attempts to “make changes to a list” for anything larger than 50–100 items, especially where there are searches or calculations being run as part of the fields being updated. That can be a heavy action, especially if the changes require searches or conditional values. Here, a recursive workflow might actually be more efficient. (We’re also planning to make this more efficient on Bubble’s end in the second half of 2023.)
- Recursive workflows scheduled every second or so. Many apps set these up to continuously monitor whether a data change has occurred. A more efficient solution might be to replace your recurring workflow with database triggers, or use webhooks to receive notifications from external services.
- Say we have a recursive workflow scheduled to regularly check for updates from an API via a GET request that terminates if no changes are found. This regularly uses a large amount of workload, merely to check for updates.
The fix: Instead, we can trigger the workflow via a POST request so that the API will send us the update only when one occurs.
Any conditional expressions on elements or workflows are consistently looking for the condition to be true. If it’s a particularly heavy action (like a database search or getting data from an external API), they’ll eat a lot of workload on a regular basis. We recommend reducing or eliminating these kinds of conditionals wherever you can. In some cases, you can also use a custom state to store a single search and reference that one search for multiple conditionals. Or you can constrain the volume of information the conditional has to check each time. For example:
- Say we have an element with a visibility conditional that searches the database to see when a particular count has been reached.
- The fix: Instead, we can create one workflow that triggers when the condition is met or unmet and use that trigger to show and/or hide our element.
Repeating groups often pull a lot of information from your database. Be mindful of what each individual row, column, or cell in the repeating group is doing with that data, as they’ll all be working simultaneously. For example, if each row is running an additional search of the database, the multiplication effect of searches within searches will drain your app’s workload.
- Let’s say we have a repeating group that’s doing a search for all ‘Clients’ in our database. But each individual cell is also doing a search for the count of all ‘Jobs’ in our database with conditionals that relate to the Client.
- The fix: Instead, we could store the Job count as a static number field on the Client data type. Then we’d be able to use database triggers to update the count only at the points where it might change, like when a job is created or deleted. That way, we can pull the count from that static field instead of searching the database each time.
Workload efficiency isn’t an exact science
Your app is unique; no two workload journeys will be the same. Don’t be afraid to use trial and error — take it step by step, examine your charts, make gradual changes, and measure the impact as you go. Experiment with different solutions to find the best workload configuration for your app.
How have you made your app more efficient? Share your experiences and tips for other Bubble users in the comments linked below.