What is that feature set?
In terms of the use of custom states, for me, what I found over the years building on Bubble, is that I would tend to forget which element I put the custom state onto, because when I first got started, I thought it best to place the custom state onto the same element from which it would need to be used, but would always forget, so now in my old age, I ensure my memory doesn’t disrupt my flow, so I place every custom state for a specific page or reusable element onto that page or reusable element itself.
Not only does that make it easy to look when in the editor to see easily all custom states in one place, it also when working with custom states in reusable elements it ensures that the custom state is accessible for actions from outside the reusable element to trigger (ie: when RE is on page and page has button that will trigger the change of the custom state value -it is not possible to target the custom state of a child element within the RE).
I think the difference in thought maybe in line of ‘do I build an optimized app’ or ‘do I build an app I find easier to build or work with’, and if choosing the latter, the extra costs of extra elements is insignificant, and so gaining just that extra slight advantage to build in a way you prefer not to is inconsequential, so better to just build how you personally feel comfortable building in.
I was taking a more historical perspective on the approach. It started in 2017. I can not speak to the mindset of the people who first put it into the Bubblesphere, but I believe it was in mid 2017 as I first came upon the use of the ‘var’ in popups for creating a list of dates (back in mid 2018) LINK to FORUM POST.
And I would say that most likely it was not introduced for maintainability for a couple of reasons. Firstly, I may be incorrect about, but I don’t think Bubble had reusable elements until around June 2018, so more than a year after when I believe the ‘var’ in popup first started to be around. Secondly, they do not really help with maintainability (unless it is a reusable element that is a global data center), they just add to the time it takes to track down where is the true source of the data, and that is because the repeating group on the page is displayed to user, so when you see that as incorrect, your first attempt and instinct as a developer is to search for the RG that displays the values, and when you find it to uncover that it doesn’t hold the search and instead references a ‘var’ data in a popup, you then need to find that popup and ‘var’ source, which just simply adds to the amount of time it would take to get in and find what you need to find.
However, the use of ‘var’ data (or just hidden data sources) is that they allow you to ensure data is getting loaded how you want to in order to help improve the performance of the application in various ways, such as loading a shorter list first and then loading in the hidden group more data after initial load. It was also mostly incorporated into SPAs that would need to load large amounts of data upfront that due to the nature of SPA, once loaded wouldn’t be reloaded, which made it easier to replicate the ‘snappy’ behavior of native mobile apps because ALL the data was already loaded.
Especially agree with the WU bit.
I’m confused ![]()
Throughout your app, it is essential that at a glance, you can tell what you are looking at
Completely agree. Naming conventions that are followed make it so easy to find things. Getting into a client app and being able to quick type to find the element or data field etc. can only be achieved with good naming convention.
Additionally, key UI elements/groups should be named usefully. For example, you may name the header ‘Group header’ or a card ‘Group user card’. However, it generally makes sense to keep the prefix (the element type) as-is, so that other developers know what they’re looking at.
Agree, keep the name of the element type intact, and when using the replace feature for replacing an element by type, ensure you change the name as Bubble doesn’t do that automatically for us. One thing I have started to do more though, is add a suffix to the end of something like “Group Header” to be “Group Header Popup Delete” as often enough in the inspector tools, trying to find the correct Group Header or whatever element, you may have multiple and not know which you are actually trying to inspect.
Against custom states
We do not recommend using custom states at all. There are a few reasons for this:
- They are functionally inferior to group variables, as they cannot be set dynamically in an elegant way
- They are not as visible as group variables in the editor
In almost all cases, anything a custom state can do, a hidden variable can do better. One notable exception is passing data between reusables.
I personally do not use custom states much in apps, so I don’t advocate for their use, but I don’t really agree with this as I don’t know what you view as benefits of a hidden variable like a RG versus a custom state as a list other than it is easier for you to see the groups in the editor, which is a valid point, and a great reason to use them for that benefit, but otherwise, I don’t see the benefits of hidden variables over custom states.
However, I do agree that making use of them to store a value you will use repeatedly in dynamic expressions is a great use of them. I got started doing this years ago and it really saves on time with crafting dynamic expressions. One other thing I do now, that I has lessened my use of hidden groups as data sources, is I don’t use them any longer to store numeric or text values and instead use an input element, especially for checkouts or other form types that require calculations.
I do not have any particular system that I think is best for naming pages
I use my-page-name so that it is not going to get turned into my_page_name by bubble because for me personally, when sharing a link, with underline text to highlight visually that it is a clickable link, the underscore is lost to the underline, or at the very least, easy enough to ‘miss’ visually, and so just for the sake of ensuring I have easy to read, easy to print, easy to share links to my app, I prefer to use my-page-name
For reusables I prefer to use Capitalized Words like Reusable Element, because Bubble doesn’t automatically change it into capitalized_words like they do with pages, so it adds just an extra visual cue to me when I look at the list of pages and REs that it is is an RE, and it also lines up with how I name my other elements like Group Header, so I like seeing it automatically applied like that when I place the reusable onto my page.
All popups are prefixed with popup.
Suffixes of Popup or Group work better for me as it keeps my reusables that relate to the same data together in the list, so I can see everything in terms of reusable elements that that data type might have, such as ‘Product Crud Group’ or ‘Product Filter Group’ etc.
All data types and option sets should be in Title Case and singular.
These should all be in what-this-case-is because of so many reasons, like for one, with data types if you use the API with, it is better to use kebab-case.
Some people will claim there ought to be a distinction between data types and option sets e.g with a prefix.
This started to be done before bubble began to group the data sources for us. So in the past, all custom data types and option sets were in just one grouping sorted alphabetically, so in order to basically group them ourselves, people began to implement the approach of a suffix of either Option Set or OS in order to ensure all option sets were grouped and sorted alphabetically while custom data types were grouped and sorted alphabetically. It was a strategy implemented to work around a lack of features from Bubble, that thankfully Bubble has implemented. But for me personally, I still set a prefix of Option Set as it just makes it easier to know that it is an option set because if you have a field on a data type that is an option set, there is no way to know and distinguish if it is a custom state or option set unless you either name the field itself or see it next to the field.
I used to do kebab-case-like-this, but reflected on it - what’s the point?
they come to form URLs used sometimes in APIs and webhooks
I want names to be readable, not technical.
Bubble forces backend workflows to be named without a space, so in terms of readability, just pick your poison of some case structure, but as mentioned above, reason for kebab-case.
Privacy rules should be applied as soon as a data type is created (or as soon as practical)
I completely disagree for so many reasons, but I’ve shared enough in the past on that, and so it definitely is a personal opinion.
Excessive focus on workload hurts clients and maintainability
Wrong.
It is not worth spending $100 of development time to save a client $1 a month in workload units.
This seems to be a failure in understanding ways to save workload units, and not necessarily experienced guidance for others to follow. I would say at this stage, my ability to save clients thousands of dollars a year on workload units for some app types or enabling a monetization strategy to be scalable on Bubble in the age of workload units doesn’t cost $100 per $1 saved. I’ve personally already invested my own time and energy into upskilling myself for building in Bubble in the age of workload units, and so it comes at no real extra cost to the client. And the ways in which WUs can be saved, in some cases, has literally taken what was a two hour task done to 20 minutes at most.
Only optimise workload issues when they become an issue.
The above contradicts the below…
- Build things the best way, not just a working way
- Virtually every problem in Bubble has multiple solutions. It is up to us as developers to first know what those solutions are, and then evaluate the best one.
- Never be satisfied with “good enough”, and you’ll thank yourself in the long run.
- Build for the needs of tomorrow, rather than the needs of today
- Linking the two above points, everything we build must be built with the client’s future in mind.
- We do not build features in isolation. Features are designed to solve core business problems - it is solving these problems that we optimise for.
- Therefore, even if the immediate requirements of a feature are fairly small and simple, we should build it in a way that supports simple future development.
External databases should not be used with Bubble*
Definitely a personal opinion, but I 100% agree on the idea of being a decent person and not steering a client wrong just to get the project.
particularly when the only reason for their use is workload savings.
They do not save workload units unless it is an extremely heavily fetched data set because of the additional workload unit costs of having to maintain two separate data types of the same type. There are now much better approaches to satellite data types that do have considerable workload unit savings and other benefits.
Don’t pass data between multiple parent groups
Great point. I remember a tip post about this from a while back.
in a repeating group, the top-level group should be a group variable
Yes, I call mine ‘Selector’ rather than ‘var’ as it is not really variable, it is the actual cells thing, and for me in my apps I generally select a thing from the RG.
The default ‘Creator’ field should never be used
I had to start doing that a long time ago, for the main reason that the feature of cookies and a non-logged in user creating data, once they register within the 72 hours, bubble would assign them as the creator of the data, but in situations in which the user was already a registered user, but just not logged in, when they go to login, they do not get assigned as the creator.
All popups should be reusable elements
I disagree. And I believe that for the most part, unless you know 100% that the reusable element will only ever be a popup, it is best practice to create the RE as a group, because you can then later place the group into a popup or floating group or onto the page directly, resulting in a much more flexible and therefore more modular approach to using reusable elements.
Make extensive use of the backend
The examples of user signup and emails are very good examples for things that should be done in backend workflows. For me, not really for maintainability as much as improving UX as when a user signs up instead of running all actions on client device we can offload most to backend which enables the user to not really be slowed down by the app having to run some workflows.
Thanks for putting this all together, it is great to point out ways in which you prefer to build and why. Hearing other developers thoughts on these types of things is great and really helps others step up their game.

