How to Structure Your Bubble App Database

What slows your app performance? How to plan your database structure? Learn more about building fast and optimized apps on Bubble.

Oct 8, 2024
How to Structure Your Bubble App Database
One of the most common complaints you can see on the Bubble forum is “Bubble is too slow, it’s not a serious platform, I’m quitting.” And a lot of versions of this phrase. 😊 But in many cases, the problem is not the Bubble platform itself. There are several common mistakes in app building that we are going to discuss in this article.
It is based on our interview with Petter Amlie, the author of “The Ultimate Guide to Bubble Performance and the founder of Amlie Solutions. Our main topic here will be database planning. We believe it will be very useful for you regardless of which stage of the Bubble journey you currently are in.

Bubble App Performance

Everyone who asks about performance has their own version of the problem that they want to solve. Performance may involve many things:
  • page load time,
  • searching for stuff,
  • making changes to big amounts of data, etc.

Why is Performance Such a Hot Topic in the Bubble Community?

There are several reasons.
  1. Bubble is not perfect.
    1. They use a server-side rendering of the page which adds a little bit of time before the page actually renders. You have a constant connection with the database. There is no cashing, there are no HTML files like you would see in a system like WordPress.
      Bubble does add a little bit of delay to your page load — no matter what you do.
  1. The second thing is, surprisingly, the flexibility of Bubble.
    1. There is a great temptation to just start building using Bubble as your notepad instead of planning in advance. 😊
      One of the most important but least technical aspects of Petter Amlie’s book is saying: “Take a breath and do some planning before you start building.”
      Because it’s hard to backtrack once you set something up for the first time. You start with a pen and paper, go through a few steps and the last thing you actually do is setting up the data types in Bubble.
  1. Another important thing is the psychological aspect. In reality, your app is not slower than other apps.
    1. Your performance and the way the app works are not the end of everything. It’s not your only feature.
      Bubble provides us with stable and performant enough apps. And our goal here is to achieve a good user experience for your app.

User-Perceived Performance

There are different ways of tricking your users into thinking that your app is faster than it actually is.
“Tricking” may not sound very good. 😊 But in fact you can see these tricks all the time and they are literally everywhere. Fancy animations, loading screens — when you start looking for it, you’ll be surprised how many apps use it. In fact, even huge companies don’t have apps that are much faster than yours. They are just very good at hiding their slowness.
It’s a smart thing to plan for in advance. Even if your application works fantastically fast right now, maybe you will add a new feature or the next thousand users which will slow it a bit.
✔️ The perceived performance is not the same as actual performance.

Planning a Bubble App Structure

Whenever you are planning an app, thinking through a smart structure of the database is probably 70% of the job in terms of optimizing for performance.
Do you have a slow app?
When people are saying “Bubble is slow” there is a 90% probability that the reason is polling the information in the wrong way, storing it in the wrong format, etc.
Let’s say your app takes 6 seconds to load. How much of the delay is actually caused by the database? Bubble’s database is not any new kind of software. They are using existing well-proven among the world's most-used database frameworks. The database itself gives you search results and responses pretty fast.
But the rendering of the data is taking the longest time in a lot of cases.
And the second thing — is everything that happens on the user’s device.
👉 For example, if you set up some kind of advanced search filters, you may be forcing Bubble to perform those filters on your device, and that can start to slow things down. It’s not going to slow you down with 5 records, but if you have thousands of them — you may even crush your browser.
Imagine working with an Excel file where every row is one record in your database and every column is a field of your data type. Let’s say you have 10,000 rows and 20 fields. Even Excel is going to slow down because it’s a lot of data to handle.
If you’re doing that on the server — you’re going to get a really fast response. If you’re doing this on the device — uh-oh!
❗️ Even if you are a professional, it might be confusing: your app can seem really fast while you are building it — because there’s just one user and there’s usually not so much data in it.

Let’s Take CRM as an Example

You are building the CRM for your company, it’s working very well. Then you bring users to it, import all your contacts — 20,000 records.
If you are trying to show every one of them in a repeating group — this is going to crush your browser. And it has nothing to do with a server: the search is fast, the download may be big but still not critical.
The rendering of 20,000 rows of information is what is going to crush your browser.
The database doesn’t add that much usually, it’s actually rendering and what you do on your device that starts to slow things down.

How to Help the End Users Render the Information in a Better and More Optimal Way?

📕 First, we quickly explain how rendering works on your browser.
If you have worked with web development you already know this, but a lot of Bubble users come from different backgrounds. Every element that you put on your page follows the hierarchical structure. It is represented visually in Bubble. You see this in your element tree on the left side of your Bubble screen which shows you the folder structure. And every single element that you see there has to be rendered somehow.
📕 What does rendering mean?
Your browser has to calculate the coordinates of everything. It has to calculate the size and position on the screen, the rendering defines every pixel that you see on the page. This is a calculation that your browser does repeatedly. And this is not just when you download the page! When you scroll it, when you click something, animate something, hide and show groups — for each thing that you do it needs to redraw the screen and to calculate a lot of stuff. And if these elements start adding up you may possibly have a hierarchy consisting of thousands of elements. It is going to start slowing an app down.
Think about Gmail, Google. It is a huge corporation. Still, they can’t show you 20,000 emails at the same time — it wouldn’t work. That's the reason you have an inbox that is showing 50 results. It’s not about keeping it tidy — your computer can’t handle showing 20,000 emails.

How Does it End Like This?

People usually don’t add 20,000 elements to one page at once. 😊 But the thing is: if you have a repeating group with just one element in it and you load 20,000 users — well, you do have 20,000 elements. It can be very easy to just multiply the number of elements by adding one single repeating group.
So, it’s about rendering: try to keep the number of elements down, try to understand that every app stops users from showing too many elements on the screen all at once.
There are apps like Excel that can handle it, but they are built specifically for it. You can’t expect Bubble to do the same thing.
So be aware that every element that you place in a repeating group is just going to multiply and grow for every user you get into the system.
❗️ The trap is — it’s not happening while you are building. It’s happening after you publish. Unless you are very serious about testing it with thousands of records.

Should You Use Lists of Elements or Multiple Elements Related to One Object?

Using lists as a performance tool doesn’t help you much because it’s not really faster.
But searches give you one really important thing such as privacy rules. This is not directly related to performance but it is still one of the most important things in Bubble that people sometimes forget. It’s easy to assume that if you show a list of things that are hidden by a privacy rule — it’s not gonna show, but it will. So the list of things will show an item even if it’s hidden by a privacy rule.
Whereas the search will never override the privacy rule.
It is wiser to prioritize security over performance. For example, Petter very rarely uses lists unless he has to for some reason. The performance gain in this case is next to nothing or maybe even nothing.
Even more, lists sometimes can become detrimental to your performance overall. Because depending on the use case, if lists get big enough — then all of a sudden you have a list of objects that has each of each list of objects.
You think that you have five or ten objects loaded to a page. But actually, you have five or ten objects multiplied by a number of elements in lists of each one of these objects.
This very quickly can turn into a hundred objects to be loaded on your page without you even knowing. And this only will leave you wondering — why do I have such a big loading time?
✔️ The advice is — no lists for performance. Using lists is usually a big exception.

How to Plan the Database and Structure of Your App

First, we are going to explain some terms that Petter uses in his book, you can also read about these in articles on his website.
  • Data Type Requirements and Conflicts

Data Concepts vs Data Types in Structuring

What is Data Concept?
This is how your users or your client see your data, how they think about them. For example, in a CRM we have vendors, clients, contacts, projects, tasks, etc. Those are data concepts.
 
notion image
 
The client here is typically your customer and the vendor is a service provider. You may notice that they are the same thing in many ways. You have several certain fields like company name, phone, email address etc.
When we start looking into this — we find out that we may not need 2 data types for these. Maybe we need only one data type called “company'' and we can separate them in some other way.
The data concept is a vendor and client, but the data type is a company.
It doesn’t mean that you always need to do that this way, but it means that in this particular example we can agree that vendor and client are almost the same things.
✔️ We shouldn’t have data types similar to our data concepts.

Requirements Conflicts

Data Weight — this is how heavy the data type is. To understand how heavy it really is you can assess:
  1. the download size
  1. how slow it’s going to be to search for it.
The easiest way to separate a data type with heavy data weight and low data weight is to look at the amount of unstructured data that it contains.
A typical example is a phone book on your smartphone. You have a first name, last name, phone number, etc. Those are lightweight fields and structured data. It is very easy to search through.
And unstructured data is one that would not be readable by a computer.
👉 Take for example a newspaper article that is saved in the database. This data outlay is not so fast to search through because Bubble doesn’t really understand what this data is — it just knows it’s a text.
And it can quickly add up a lot of data over time. The weight of one article is small, but when we download hundreds and thousands of articles — we have to download tens and hundreds of megabytes.
So, unstructured data is not very search-friendly because it can add a lot of data to each record in the data type.
The third term that we use is data type requirements and data types conflicts.
👉 Take for example data type “article”. It contains a lot of unstructured data because it stores a full article. (Maybe even more taking into account all comments to the article, etc.)
You need this data type to be searchable efficiently — users are going to search for articles all the time. And here you can see an example of the conflict:
We have two requirements for this data type: it has to contain a lot of unstructured data and also it has to be searchable fast. But we can't have a data type that's both data-heavy and efficiently searchable. Those two are competing with each other.

The Solution for Effective Structuring

So we introduce you to the fourth term called the satellite data types. These are extra data types that you set up to overcome these conflicts.
An important notice — some users make a mistake here using Bubble as their notepad and moving from data concepts straight to setting up the data types.
❗️ It’s necessary to include in your workflow setting up Data Concept Requirements first.
Map out the requirements and then move to data types is the optimal decision.
 
notion image
 
Let’s take a look at an example CRM again.
  1. Your client tells you his/her data concepts like client and vendor. The next step is specifying requirements for these data types.
  1. And realizing these data concepts have a lot in common you see that you can merge them into one data type: company.
  1. If this data type turns out to be data-heavy, the solution is the satellite data type which solves our requirements conflict.
In this case, the conflict is that we need a heavy data type to be easily searchable. So we add a company search satellite data type which we can call a search container or data container.
It serves two different purposes. Our first data type “company” is heavy, meanwhile, this one is really lightweight. It only contains the data needed to return a search result. So if you're searching only for a company’s name for example it could potentially just include the single field “name”.
So when users search this record on your Bubble app, the Bubble first returns them a list of satellite data types, and then when the user selects a specific one — it downloads just one record. And if it’s only one record — a heavy data weight is not a problem. It would affect performance in the case of downloading hundreds of records.
❗️ For now, Bubble is downloading all the data even if you are not showing it.
Take for example a blog post again: when you are showing the repeating group with blog posts titles you may think that it’s very lightweight. The rendering may be quick but still, you are downloading the full blog post of every record.
One more use case for search container satellite data type is connecting it to several different data types to ease the search.
Let’s say if you have five different data types you would have to place one search and one repeating group on top of each of these data types Whereas when you build one satellite data type that applies to each one of them you could force that into one search. 👉 Remember TripAdvisor? You can search for Countries, Cities, Hotels, Restaurants, etc. — all from one search bar! 👉 Another example is searching through a CRM to find customers, tasks, or projects. Again, all from the same bar.

Wrapping Up

We hope this article was useful for you. If you have any questions — bring them up on Zeroqode forum. 😊
Thanks for reading, you can also watch the recording of Zero Code Series on our Youtube channel. Petter also has an upcoming book on Bubble.io security. You can see all the Bubble books he’s released so far on his website.