How to Speed Up a Slow Bubble App

How to Speed Up a Slow Bubble App

Founder of Goodspeed

A slow Bubble app is rarely slow for one big reason. It is slow because of a dozen small decisions that made sense at the time and quietly stacked up. A search that scans every record, a repeating group that loads a thousand rows, a page that pulls data nobody looks at, a backend workflow that runs one item at a time when it could run in batches. On their own each is harmless. Together they turn a two second page into an eight second wait, and users feel every extra second.

The good news is that Bubble performance is diagnosable. You do not have to guess. You can measure where the time goes, separate a workload unit problem from a page load problem, and fix the biggest offender first. This is exactly the discipline we bring to every app we inherit or build from scratch, and it is why our clients stop dreading their own dashboards.

This guide walks through how to find the real bottleneck and fix it, in the order that gives you the fastest wins. We will cover searches, repeating groups, database structure, page weight, and backend workflows, with the practical detail that actually moves the needle rather than generic advice you have read ten times before.

Find the bottleneck before you touch anything

The first mistake teams make is optimising the wrong thing. They rebuild a page that was never the problem while the real cost sits in a nightly workflow nobody watches. Before you change a single element, work out whether you have a page load problem or a workload unit problem, because the fixes are completely different.

A page load problem shows up as slow first paint, spinners that hang, and repeating groups that take seconds to fill. A workload unit problem shows up in your Bubble billing and in backend workflows that eat capacity. Open the Bubble app metrics, look at your WU consumption by source, and use the browser network tab to time the actual searches on your slowest page. Measure first, then fix, and you will never waste a day polishing something that was already fast.

Fix your searches with constraints, not filters

The single biggest cause of a slow Bubble app is searching badly. When you use a Do a Search for and then apply a colon filtered on top, Bubble pulls the entire list from the database and filters it in the browser or on the server after the fact. On a small dataset you will not notice. On ten thousand records you will feel it, and your workload units climb with every extra row scanned.

The fix is to push your conditions into the search constraints instead. Constraints run at the database level and use indexes, so Bubble only ever returns the rows you actually need. Reserve colon filtered for the rare cases where a condition genuinely cannot be expressed as a constraint, such as filtering on a calculated value. Every filter you convert into a constraint is a direct reduction in both load time and workload cost.

Never run Do a Search inside a loop

A search inside a repeating group cell, or inside a backend workflow that runs on a list, is one of the most expensive patterns in Bubble. If a repeating group shows fifty rows and each cell runs its own search, that is fifty separate database queries for one page. Multiply that across a busy app and you have manufactured your own slowdown.

The answer is to load the data once at the parent level and reference it inside the cells, or to restructure so the relationship is stored directly on the record. When a workflow needs to act on many items, schedule it as an API workflow on a list rather than looping searches one by one. Removing nested searches often takes a page from several seconds down to under one, with no visual change at all.

Store fields instead of recomputing searches

If your app constantly searches to answer the same question, store the answer. A common example is showing a count, such as the number of orders a customer has placed. Recalculating that with a search on every page view is wasteful when you can keep a running field on the customer record and update it when an order is created or removed.

This is a deliberate trade. You accept a small amount of redundant data in exchange for far cheaper reads, because reads happen constantly and writes happen rarely. Denormalising a few frequently read values is one of the most effective performance levers in Bubble, and it is the kind of structural decision that separates an app that scales cheaply from one that gets more expensive every month.

Tame repeating groups with pagination

Repeating groups are where slow apps go to die. A repeating group set to load every matching row will happily fetch a thousand records, render them all, and hold them in memory while the user scrolls past the first ten. That is a huge amount of wasted work for data nobody will ever see.

Set your repeating groups to a fixed number of rows and paginate, or use a load more pattern that fetches the next batch on demand. Bubble only requests what is on screen, first paint arrives quickly, and workload units stay low because you never pull rows that go unread. For long lists this is the difference between an instant table and a page that visibly struggles.

Never nest repeating groups if you can avoid it

Nesting a repeating group inside another one multiplies your data load in a way that is easy to underestimate. An outer group of twenty rows, each containing an inner group of twenty, is four hundred cells rendering at once, and often four hundred searches behind them. Performance falls off a cliff and the page becomes almost impossible to reason about.

Where you genuinely need grouped data, look at restructuring the display so the inner data is pre-grouped, or load it on demand only when a row is expanded. Flattening the structure, or lazy loading the detail, keeps the initial render light. Nested repeating groups are one of the first things we untangle when we take over an app that has slowed to a crawl.

Structure the database so reads are cheap

Your data model decides how hard your searches have to work. If everything lives on one bloated data type with forty fields, every read carries weight it does not need. Splitting rarely used or heavy fields into a satellite data type, linked back to the main record, keeps your core searches lean because Bubble only loads the satellite when something actually needs it.

Think about which fields are read together on your busiest pages and keep those close, while pushing occasional or bulky data such as long text and logs off to the side. A well structured model is invisible when it works and painfully obvious when it does not, and getting it right early is far cheaper than restructuring a live app under load.

Avoid giant lists stored on a single record

Bubble lets you store a list of things directly on a record, which is convenient until the list gets long. A field holding thousands of linked items becomes slow to load, slow to modify, and prone to save conflicts when several actions touch it at once. It is one of the most common scaling traps in the platform.

The scalable pattern is to reverse the relationship. Instead of a project holding a list of a thousand tasks, each task holds a link back to its project, and you search for tasks by project when you need them. This keeps individual records small, makes searches indexable, and removes the contention that long embedded lists create. It is a foundational habit for any app expected to grow.

Use privacy rules to limit what loads

Privacy rules are a security feature first, but they also shape performance. When a privacy rule restricts which records a user can see, Bubble never sends the excluded rows to the browser in the first place. That means less data over the wire, faster searches, and a smaller attack surface, all from the same setting.

Configure privacy rules so each user only ever receives the records they are entitled to, rather than pulling everything and hiding the rest with conditions. Hiding data on the page still downloads it, which is both slow and unsafe. Rules enforced at the database level are the correct place to draw that line, and they quietly improve performance as a side effect of doing security properly.

Trim the page with conditional loading

A heavy page loads slowly even when its data is efficient, because the browser still has to build every element. Tabs, modals, and hidden sections that load their data on page open are doing work before anyone asks for it. If a user opens a page and only ever looks at the summary, there is no reason to load the contents of five other tabs they never click.

Use conditions so groups only load their data when they become visible, and defer offscreen content until it is needed. Bubble supports this pattern well, and it front loads only what the user sees first. The result is a fast initial render, with the rest arriving quietly in the background as the user interacts, rather than all at once up front.

Optimise images and cut unused plugins

Images are often the heaviest thing on a Bubble page and the easiest to fix. A full resolution photo squeezed into a small avatar wastes bandwidth on every load. Serve appropriately sized images, lean on Bubble's built in image handling, and compress before upload so the browser is not downloading megabytes to display a thumbnail.

Plugins deserve the same scrutiny. Every installed plugin can add scripts to your page whether or not you use it, and a handful of forgotten plugins can noticeably slow first load. Audit what is actually in use, remove what is not, and be selective about adding heavy third party plugins for features you could build natively. A lighter page is a faster page, and this cleanup usually takes an afternoon.

Optimise backend workflows and watch workload units

Backend workflows are where workload units quietly disappear. A recursive workflow that processes records one at a time, or a scheduled job that searches inefficiently, can burn more capacity than your entire front end. Because it runs out of sight, it often goes unnoticed until the bill arrives or the app slows during peak jobs.

Batch your work where you can, schedule API workflows on a list rather than looping individual actions, and stagger heavy jobs so they do not all fire at once. Watch your workload unit consumption by source in Bubble's metrics and treat any spike as a bug to investigate. Efficient backend workflows keep both your performance and your costs under control as the app grows.

Make performance a habit, not a rescue

The apps that stay fast are the ones where performance is considered at build time, not bolted on after users complain. Every new search gets constraints from the start, every repeating group is paginated by default, and every backend job is written to batch. None of this is exotic, it is just discipline applied consistently across the whole app.

If your app has already slowed down, the path back is measured and methodical. Find the bottleneck, fix the biggest offender, measure again, and repeat. Most apps have three or four changes that account for the majority of the slowdown, and clearing those transforms the experience. The techniques above are the same ones we apply to every product we ship and every app we are asked to rescue.

Fast Bubble apps are built on clean data

A slow Bubble app is a solvable problem, not a life sentence. The slowness almost always traces back to a small number of expensive patterns, inefficient searches, overloaded repeating groups, a strained data model, and wasteful backend jobs. Measure honestly, fix the biggest offender first, and re-measure, and you will recover speed without rebuilding from scratch.

Do this well and performance stops being a firefight and becomes something your app simply has, because the right habits are baked into how it was built. That is the standard we hold ourselves to on every product. If you want a certified Bubble team that builds products you own, book a free call with our Bubble team.

Harish Malhi - founder of Goodspeed

Written By

Founder of Goodspeed