Things I've learned while building complex apps

Hey people

I’ve picked up some tough lessons over my soon-to-be two years of Bubbling. I thought I’d try to list here some Do’s and Dont’s that I find useful. If you disagree with one or more, feel free to shout out: I’m not saying my methods is to be considered “best practice”, just things that I’ve found to work for me.

Some of them may seem obvious, but to me they weren’t. Also, they won’t fit all apps of course, some of the rules might apply to yours, some may not:

Here goes:

DO plan your app design before you start building
The eagerness of building quickly in Bubble has countless times made me rush into designing the site without proper planning. Designing things from scratch is quickly done in Bubble, but making changes when you already have a lot of elements in place is cumbersome and time-consuming as hell. Remember also that every new element you add will make your app slower. Every single one. Poorly planned site usually end up with groups nested in groups nested in groups for no reason, invisible elements that mess up your responsiveness, etc etc.

DO plan for mobile first
This is one of those mantras that I’ve heard a lot over the years, but still managed to ignore until I learned it the hard way. Building a complete app, and then afterwards trying to make it fit on a small screen is a nightmare. Build it for a small screen first, and then allow it to expand for a bigger one. Note: the default mobile screen width in the Bubble responsive engine is 375px. However, many mobile screens on popular models are smaller than that. 320 px is a good width to design for.

DO learn the responsive settings properly
I thought I knew it pretty well, but over months of work I’ve had to swallow my pride a lot of times when I discovered that what I thought were weaknesses or bugs in Bubble, was myself not properly understanding how the responsive engine works. Why is this important enough for its own point? Because it changes the way you think when you design the app. Just like the above points, you’ll be thinking ahead, instead of retracing your own steps.

DO think about how your workflows and database structure will work with 1, 10 and a 1000 users
Something that works with one, two or five users can be virtually impossible when you reach 100. Describing what this means is outside of the scope of this post, but trust me, actions such as “Copy a list of things” and lots of “Do a search for” put a huge strain on the server. Think about how each and every action affects your performance, and what you can do to minimize the strain. Again, it’s easier to do it right the first time then to make changes later. This thread should be mandatory to read.

DO use Reusable Elements
Reusable elements will, as the name suggest, let’s you use identical groups of elements more than one place in your app, including across pages. Performance and memory use put aside, there are several big upsides to this: in more complex apps, two things become very cluttered in Bubble: the Element Tree and the Workflow editor. A Reusable Element doesn’t only contain the elements within, but also the workflows associated with those elements. This means that you can keep your page nice and tidy, while elements and workflows contained within a single Reusable Element. How do I “communicate” with elements inside a Reusable Element? Use states in the “root” element, which are accessible outside of the element as well.

DO use Custom Workflows
What are Custom Workflows for? For practical purposes in my view, the have two important meanings: 1) avoid repeating workflows, and 2) know where to find your workflows. Here’s an example: you have an app with a simple text editor. In this app, you have a Save button and a File -> Save dropdown menu that perform the same task. Instead of assigning a separate workflow for each one, you create a Custom Workflow called “Save document”. Not only does it decrease load time and keep the workflow editor nice and tidy, but if you need to change something (let’s say you want to show a success alert when the saving is done for example), you only need to change this in one place. Another tip I use frequently is to nest Custom Workflows, so that running one custom workflow triggers another custom workflow (sometimes based on specific constraints).

DO clean up the app before you start building
Bubble comes with a bunch of different styles when you create a new project. For me, they usually turn out a mess, and I’ve started to delete most of them and use the planning process to see which styles I actually need. It’ll make it a lot easier to give your app a consistent look when you don’t confuse yourself with a zillion different styles.

DO write down important info when you plan and build your site
How wide is the margin? What is the page’s minimum width? How many pixels do you use from header to content? At what width does the margin collapse? Use a spreadsheet or similar to note down small stuff like that. Again, it will help you keep your site a lot more consistent.

DO minimize plugin use
Plugins are great, but they add to your loading and processing time. Uninstall the one’s you’re not using and think twice before adding something that’s “nice to have”

DO think about how the user experiences your app
Many new Bubble users are frustrated that their app seems slow, and many complain the forum. I’m not gonna pretend that there are no speed issues with Bubble, but when you actually start looking at other apps, you might realize that the difference is not in the loading time, but in the UX. Here’s a strange thing about people: we accept loading time as long as we have something to look at. Many of the world’s biggest websites and apps are actually not that blazingly fast, they’ve just put a lot of thought into how to keep the user’s attention while the content is loading. Spinning icons is a dead simple way to make loading time more bearable, but there are many other ways to experiment.

DO prepare your app for translation
This is of course only for the apps that might need it. Don’t add text directly to your element, instead use the (somewhat forgotten) Settings/Language tab, which is actually a really powerful multilingual feature. I do it for every app, as I never know if a translation may be needed in the future.

DO remember that hover effects will not work on mobile devices
This one’s so obvious; but I’ve sometimes made significant features in my apps depend on hovering with the mouse, only to realize I have to create a separate solution for phones and tablets.

DO hide elements until they need to be displayed, not the other way around
Don’t hide your elements when they’re not needed – show them when they are. This means unchecking “This element is visible on page load”, and using Conditions to show it when needed.

DO learn to use the Privacy tools
You have an HR app with multiple clients. In this you have a repeating group with a list of the client’s employees. In the Do a Search for, the Client is a constraint, making sure that he only sees employees from his own company, and not for all clients in the app. Secure, right? No. For example, a network error may result in the Client data type never loading. In that case, the Repeating Group will treat the constraint as empty, and show ALL employees. An unforgivable security glitch! The privacy settings will make this a lot more secure. Take the time to learn it and implement it before going live.

DO use conditions as an extra security measure
Let’s use the HR app as an example again. It has a list of employees with their salary, that should only be visible to logged in users. A “User is logged out” workflow and redirect to another page can stop someone from seeing the page when not logged in, sure. But there are numerous reasons as to why that workflow never runs: connection drops, server error, Bubble bugs… instead, make all important groups invisible on page load, and use a condition to show it only if the user is logged in (or whatever other criteria). Obviously use privacy settings etc. as your main security measure, but this adds an extra layer of protection.

DON’T use popups as a security tool
User logged out? Just show a popup with a blurred or colored grayout and a sign-in form, right? Wrong… a popup, including its grayout, can easily be removed with an ad blocker, exposing the page below. It’s not secure, and not supposed to be, so don’t use it that way.

DON’T overlap elements
In some cases, you may have to of course. But in general, overlapping elements makes responsiveness and page height confusing. Let’s say you have two groups, tab 1 and tab 2. One is visible when the other is not. Instead of having them overlap each other, place them so that the second group top border begins where the first groups bottom border ends, and have the group collapse its height when hidden. This way your page height will adjust to the content, instead of remaining constant.

DON’T get caught in the eternal improvement loop
This one’s a big one for me. The urge to constantly improve something just because you can, and pushing release forward week after week after week. Make it work, you can improve it later.

I gotta call it a night, but I’ll keep adding points as I learn something new or remember something worth noting. I hope this can be of some help to someone, and feel free to contribute hard-earned lessons :slight_smile:


It’s all about groups :wink:


It truly is!

The idea that groups without any content can be used as “spacers” to control responsiveness was probably the biggest eye-opener for me, and one of the things I really wish I knew earlier.

Also, the very simple practice of using a calculator when setting element coordinates and responsive rules instead of trying and failing with the mouse will make it a lot easier :slight_smile:


Nice post, @petter

Note that the responsive editor mobile view has width 375px. If designing to this minimum, its larger than a lot of phones (Samsung Ace 3, iPhone 4, some Nokia Lumia) and causes unwanted sideways scrolling. I find a better minimum is 320px.


Is there an easy guide to learn about responsiveness in Bubble?


this is cool @petter
do you mind if we add it to our internal manuals? :slight_smile:

1 Like

Point 2 (do the math), I wholeheartedly agree with. (And Point 0, that you should think about mobile/responsive - and test it - continually.)

However: I find the use of empty groups (like the “space to squeeze” spacer used in the Bubble wizard-created footer) just plain EVIL. That’s just very hacky and unpredictable. Much better to do the converse: Don’t squeeze a space to force responsive behavior. Put the elements that you are trying to get to stick to the left and stick to the right and GROUP them. Then just make the left one left margin static and the right one right margin static. So much easier to keep track of and understand.

</end unsolicited advice>


I use the ‘current width’ condition in the editor to set all my responsiveness.

I’ve looked at the responsive tab but I don’t really get the hide rule ‘if parent element is x width’ but how do you determine the parent element x width when it is also responsive?

I use to get accurate browser width and a calculator to get min% width but I don’t really get why there is another parent element x width rule in the responsive tab when you can just use the current browser width tab in the editor.

Can you explain that?

1 Like

Another way to handle responsiveness on the smaller width devices is to have groups show when width is a specific width, while hiding your main larger groups. Some things just need completely different spacing and sizing at the phone width. Saves me tons of time as you are simply stacking groups instead of adjusting every detail.

Also, instead of dragging things out of a group on accident, use the arrow keys on the keyboard to get it all the way to the edge without going out. :slight_smile:


Thanks for the feedback. I’ve done what you’re describing here, but I’ve found use for the spacer groups still. I may need to stand corrected on that one, just goes to show that the learning’s not complete!

I’m just happy if it can come to use, you may do with it whatever you want :slight_smile:


You can see the width of elements and containers as you adjust the page width in the responsive editor. The difference between hiding elements in the regular editor and responsive is that the responsive allows you to collapse the width.


There’s almost always multiple ways to accomplish the same thing in Bubble (thankfully), but the squeeze trick (while super interesting) is also very obtuse – but just my opinion.

Another random resource for responsive design that can be helpful to new Bubblers is any of the documentation or learning tools around Adobe Muse’s responsive capabilities. That tool (which was unfortunately recently end-of-lifed) had a great set of responsive settings that are quite a bit like Bubble’s and there’s a good deal of material around that.

1 Like

Great post @petter - would you mind elaborating on how you use the privacy settings to avoid the issues you mentioned?


Learned that too: Parallel processing :wink:
As Bubble is made of NodeJS, it make sense to use it to speed up our apps. This is my discovery… Parallel actions is way faster

1 Like

Great guide. It’s refreshing to see I’m not the only one that had to learn those tips the hard way :slight_smile:

Hiding by default will also consume less resources at load and if you are building an authorization “engine” it’s a must.


Thanks for the tip JohnMark. It’s my experience that API workflows are delayed compared to in-app-workflows. How is your experience regarding this? I’ve been hesitant using API calls too often because of this, but I may have implemented in the wrong way, or it may have improved since I last tested it.

Sorry for the late reply, as I have been traveling.

The privacy tools work very much in the same way as workflow conditions. Let’s say for example (using the HR example again), that you have the following in your database:


  • Name (text)

  • Administrator (Use)

  • Secret info (text)

So you have a page where you want to show and edit the company name and the secret info, but only if you are the administrator of that company.

In that case, you can define a new role for the Company data type called Administrator which looks like this:

When: This Company’s Administrator is Current User
… and then set the different rights of users that fit the criteria. This way, any user who doesn’t fit the criteria is “physically” (not literally…) kept from seeing it, even if you make a mistake in a field or repeating group. Note that currently Bubble doesn’t support subfields (such as this Office’s Company’s Administrator), so you have to do some planning in your database for it to work.



Before it was true, I noticed it. Now it sounds to be faster due to newer way Bubble split task (cpu) thing. Smaller the schedule workflows, faster is everything. That’s my observation until now :wink:

1 Like

Awesome, I’ll experiment with it!

I’ve updated the list with two more points about

  • Custom Workflows
  • Reusable elements
1 Like

I’ve played around more following the advice you gave, and I agree: most situations (if not all) can be solved without the use of extra “spacer” groups. Thanks again for the feedback, it just cleaned up one of my pages of a lot of unnecessary groups.

1 Like