I have an internal list of ‘Golden Rules’ that I use to inform my Bubble development that I’ve picked up from community members or from trial and error.
I thought it’d be fun if we could crowd-source some more Bubble tips + tricks and make a big list!
What’s missing from here? Let me add it on!
- From @nsykes: Never leave a slug empty. If a data type doesn’t “need” slugs, set one anyway and just
Calculate formula
→Generate random string
to a 10 character alphanumerical string. example.com/test/38fn18sd94b looks better than example.com/test/39230423930294830x2014982309432094823 - From @nsykes: When you can, have the client-side identifier of a piece of data be the slug. For example, the order number of a DT_Order should be the slug. If the client-side identifier has caps in the ID, consider changing it to make it align with slug naming conventions. Discrepancies between spaces/underscores are OK.
- From @nsykes: If you HAVE to run a ‘Do every X second’ workflow, there better be a conditional set at the workflow level (and not at the first step of the workflow) to make sure we’re only incurring WU when we absolutely need to.
- From @nsykes: In most cases, the best way to do user permissions in Bubble is to set however many roles you need (employee, manager, admin, etc.) as an option set in Bubble and add a corresponding field in the User datatype. Privacy rules + visibility of elements can be plotted against this.
- From @nsykes: Naming conventions are very important for keeping track of stuff.
- Datatypes should have a DT_ prefix (DT_Company, DT_Category, DT_Ledger, etc.)
- Satellite Datatypes should have an SAT_DT_ prefix.
- Option sets should have an OS_ prefix (OS_Roles, OS_Color, OS_Condition, etc.)
- Custom events should have a CE_ prefix (CE_AddItemToPurchase, CE_AdjustReversePagination, etc.)
- Reusable elements should have a RU_ prefix (RU_header, RU_loadingpopup, etc.)
- Datatypes should have a DT_ prefix (DT_Company, DT_Category, DT_Ledger, etc.)
- From @nsykes: Conditions are checked from left to right in Bubble. To save on WU, place the conditions that will take the least WU to check first.
- From @nsykes: When you first login for the day, create a savepoint.
- When you log out for the day, create a savepoint.
- When you’re about to do something stupid (and you know it’s stupid), create a savepoint.
- From @nsykes: If your app has user profile photos, solve against empty pictures by autopopulating empty image inputs with the DiceBear API, which generates custom profile photos. It’s as easy as setting the image URL to ‘
https://api.dicebear.com/7.x/initials/svg?seed=Current user's full name
’ or your database equivalent. They have many different styles, noted here. - From @ranjit and @chris.williamson1996: If you have to consistently run an advanced filter, or use :merge, :filter, :minus, :plus, or have expressions that are over 3-4 layers deep to do a search, there’s a high chance you are using bad optimization practices and can solve it with a database restructure.
- From @gaby: When filtering a Repeating Group in Bubble, use daisy chain filtering method for the fastest result. Here’s a great video from @Andrew.Vernon: x.com
- From @nsykes: If you want to toggle DT_Order’s ‘Completed’ using a single button/element, run: change ‘Completed’ to If
'DT_Order's Completed' is no.
- If ‘Completed’ is no, then it’ll get set to ‘yes’.
- If ‘Completed is yes, then it’ll get set to ‘no’.
- From @nsykes: If you have a Datatype with many fields and have to display a Repeating Group with fewer than half of all of it’s fields, use a Satellite Datatype to do so.
- From @nsykes: If something is not visible, 9 times out of 10 it’s a privacy rule issue.
- From @TipLister: Need to get specific data about the country a user lives in (image of their flag, their currency, etc.)? A simple API call could be to
https://restcountries.com/v3.1/alpha/[Current user's address:extract country]
- From @nsykes: ‘Dummy run’ crucial plugin actions on page load. You may have noticed the first time you run a plugin after not using it for a while, it takes a minute to execute. If you just run a test action with dummy data on page load, the first time your user engages with the plugin and triggers an action, it’ll run at normal speed.
- From @adamhholmes: Searching for “
DT_Order's first item:is empty?
” is faster and less WU intensive than searching for “Do a search for DT_Orders:count is 0
”. If you want to earn even more brownie points on WU intensiveness, check out Adam Holmes’ post on a third option.- @adamhholmes has clarified that this is only true because of a bug with Bubble; I’ll update this post when the bug is squashed.
- From @chris.williamson1996: SPA (single-page applications) should ALWAYS have the main page data type as “navigation” too allow for forward\back browser nav, nice slugs, and all pages should be reusable elements to cut down on clutter on main page & keep editor performance.
- From @chris.williamson1996: If you get stuck and think your only option is to move to an external db there’s a good chance you’re wrong. Ask the forums for help!
- From @chris.williamson1996: Never leave a data field “default” option empty for number values (set to 0) or booleans.
- From @chris.williamson1996: When starting your app make your decision up front on how you handle word casing & trimming.
- Most of the time [Chris] personally always :lowercase everything in database & use :capitalizedwords for things such as names, company names, etc. This ensures consistency in bubble since searches are case sensitive. Most all items should be saved :trimmed.
- From @chris.williamson1996: If you use Scheduled workflows on datatypes ALWAYS record scheduled time when scheduling and Completed time when completed (if you use for multiple things opt for a “log” datatype instead). Admin dash should have a display of count items that are past schedule time and completed time = empty.
- From @chris.williamson1996: GET calls to your API providers are there for a reason. Don’t just use your database as your first line of reference or rely on webhooks. mostly for payments but in all API instances. For major parts of your app run daily, weekly, or monthly checks to ensure your data is in line. Ex) you don’t have items marked in your database as active while stripe as them marked as expired. For these I tend to prefer alerts rather than db changes so I can see the errors rather than just expecting it to fix itself.
- From @chris.williamson1996: Plugins your apps core features rely on should be built in house after MVP. If this can’t be done you must make contact with the plugin creator in order to see what management looks like & have a backup option on hand.
- From @chris.williamson1996: Privacy rules aren’t just for security. They also play a big roll in app speed on larger apps. No app should ever hit production without privacy rules setup.
- From @chris.williamson1996: Most app should never be launched public without google analytics & Facebook pixel tags. We live in an age where data is more valuable than gold.
- From @chris.williamson1996: Login/Signup pages should be separate. The marketing team will thank you.
- From @chris.williamson1996: When working with multiple developers documentation is important. If on time/budget constraints.
- Notion documentation, or equivalent (best)
- Loom video documentation (better)
- No documentation (unacceptable)
- From @chris.williamson1996: Cash flowing production apps should ALWAYS have a backup of the database on an external source.
- Bubble may claim to have full backups but twice in [Chris’] life [has he] lost unretrievable data by bubble due to bugs even with supports assistance.
- From @chris.williamson1996: Popups should never be used as “pages”. Keep those for alerts, create, edit, delete actions.
- From @chris.williamson1996: In your day to day life pay attention to how major companies build & navigate their apps. Pay attention specifically to page utilization, element types being used, & URL structuring with use of params.
- From @AirDev: When running API workflows in Bubble, the number of items that the workflow has to execute upon has a greater impact on performance than the size of each item. (source)
- From @djtochner: When creating a looping workflow, make sure you have a safety switch/condition that will shut the workflow down so it doesn’t suck all of your capacity. (source)
- From @georgecollier: If you find yourself frequently needing to dynamically specify which field to modify on a type, you probably need a new data type where that field is an option set.
- For example, for order statuses, instead of having fields ‘dateOrdered, dateAccepted, datePacked, dateShipped, dateDelivered’, have a List of Order Statuses where Order Status contains the date and the status (Ordered, Accepted, Packed etc option set). The exception might be dateOrdered which should also be kept on the Order data type for efficiency purposes.
- From @georgecollier: Anything not protected by privacy rules is public, even if you don’t show it in your app.
- From @georgecollier: Current user’s logged in is not a sufficient privacy rule if anyone can create an account.