They preload and cache automatically, making dropdowns super snappy.
They keep your database lean and tidy.
They simplify condition mapping—much more intuitive to work with.
But the drawbacks are real:
Because they’re always cached, having a lot of option sets can bloat your app’s cache—especially if you add heavy fields (description per option…) or have lots of options per set.
Each option set is siloed, limiting flexibility.
Over time, you’ll accumulate dozens (or hundreds) of option sets, forcing you to duplicate similar logic across many of them.
Imagine you have multiple “status” option sets for different data types, and now you want to add colors and icons. You either add those fields to every option set or build complicated front-end conditional logic like “if option A, show green + icon A”—which quickly gets messy.
Now say you want a custom dropdown that displays those colors and icons. You’d have to build one per option set or hack together a clunky system that passes separate lists of names, colors, and icons and then reassembles them inside a single reusable dropdown. Not ideal.
A better solution? Use an option set data table.
This lets you:
Share fields, logic, and reusable UI elements across many option sets.
Allow users to create and edit custom options (colors, icons, names) right from the front end.
Can update option sets without deploying since they are data
Easier localization by adding fields and filters
Better integration with external APIs since data have ids
Granular access control with privacy rules
Easier additional data storage
All fields are visible in the table and you can create table views
Can bulk import/export/update options since they are data
Can log versioning/history
Easier filtered display since now you’re using search for instead of all options filtered by
Much more scalable for large and complex apps
Automated workflows on changes
Better for multi-tenant apps since options can be owned
Easier for hierarchy options
Searchable with algolia and integrates with other plugins etc
But, heads up:
No automatic caching or preloading for data tables.
Condition mapping is trickier—you have to search by ID or slug manually.
Bubble’s editor makes working with this more complicated, due to its abstracted logic and limitations
Increased database calls (searches)
The benefits multiply if you have lots of similar option sets needing the same logic. For example: 50 status/type option sets across 50 tables.
With a data table, you can build reusable components—dropdowns, cards, tabs, edit popups—that plug into any part of your app.
It also simplifies workflows referencing multiple option sets at once. For instance, I built an automation system (tasks, emails, etc.) triggered by status changes. Because all status fields across different data tables come from the same option data table, the logic is much cleaner, simpler and easier to maintain.
Major downside: Bubble doesn’t preload or cache data tables (aside from some awkward workarounds). This means using option sets as data tables will increase the number of searches on a page, impacting performance and WU. Bubble also requires some jumping through hoops to get custom dropdowns and related elements working smoothly—but the upside is you only have to figure it out once, since those components are fully reusable across your app.
There is another choice between Option Sets and Custom Data Types. It can also be API Objects. I use these in my apps to get around limitations of Option Sets, like complications of updating/maintaining them and restriction on user creation, but maintain the benefits of them loaded automatically without needs to touch the database every time they are needed.
I think ultimately, wiser decisions around when and how to use either Option Sets, Custom Data Types and API Objects is something people should try to focus on.
I do this for proprietary data that needs to be gated behind privacy rules. I believe Bubble does some “magic” behind the scenes (indexing) to make these load faster when they’re used all the time, although it still costs the same amount of WU.
Pretty negligible, if you look at the size of the data being downloaded altogether.
You’ve missed the easy option.
The data type it is associated is a property of the status. Each status could be used by multiple data types, though probably not all statuses apply to all data types.
Let’s suppose two statuses for Shipping (e.g a package) and Order.
Status Type option set
Shipment
Order
Now, Shipment requires:
Draft
Shipped
Out for delivery
Completed
Cancelled
Order requires:
Draft
Awaiting payment
Confirmed
Completed
Cancelled
Lots of overlap.
Status option set
Draft
Shipped
Out for delivery
Completed
Cancelled
Awaiting payment
Confirmed
The ‘Status Type’ is a List of Status Types attribute on the Status option set.
In UI, you filter the option set’s options based on the type you are dealing with.
So:
The type of status is a property of the status itself, but all statuses are statuses, and can be defined in one option set.
A common example I see is people with single-page apps using a different option set for each page’s tabs, which is fundamentally silly.
Instead, the wise approach would be to have one option set for all tabs and then have a pages option set, where each tab option can have a list of pages that it belongs to. This way, on each page, you just display a filtered list of tabs.
I do the same, i have 1 option set for similar datatypes, with some additional datatype specific options. Add an attribute to those that I use to filter wherever I need it.
The thought of option sets being hardcoded did come to mind a while back and I did try storing option sets as datatypes.
Decided it wasn’t worth the time and effort managing option sets stored in the DB and only use that for sets that need to be secure or user customizable.
I’ve used this approach, and it works well for simple builds. However, once you introduce option set attributes, things become much harder to manage. Since attributes are hidden and not displayed in a table format, working with them in complex logic becomes cumbersome.
For example, using a single option set like Status with a Type attribute is fine for small apps, but it doesn’t scale. Similarly, the common Tab option set works in simple apps, but it quickly breaks down when dealing with:
Dozens of pages or sub-tabs
Tabs reused in different components
Tabs that only apply to a few pages
You end up with a massive, disorganized list of tabs that are hard to manage without a clear, tabular view of attributes.
A more scalable approach for tabs is to create a reusable element that accepts a comma-separated list of texts. This allows full flexibility per page or component without having to manage a separate data source and without having to repeat logic - just pass in the list of texts and it’s done. The main drawback is needing to manually rename tab labels logic, but this is usually minimal—usually only tied to one conditional group.
Option sets are great for simple use cases, but once option sets needs attributes, they’re usually better off switching to a data table. Managing data in tables is far easier, especially as the logic grows in complexity.
As with anything in bubble/app dev there are lots of different ways of achieving largely similar results. Here I’m sharing an alternative solution that I’ve found to be a much better way of handling complex logic when it outgrows the limitations of options sets and their attributes.
Option sets without attributes is like a table without columns.
You’ve just described an editor UI issue, not something that’s really fundamental to the maintainability of the app as a whole.
Quite the opposite! It is (one of the) only ways to manage these maintainably at all in a large SPA! You can also have custom conditions such that some only show when a certain condition is met (any arbitrary condition!) using some cool filter constraints.
This is a simple example without any subtabs, but subtabs would be handled by having a tab with a parent attribute!
My main peeve with option sets is that attributes are not displayed in a table which for me makes attributes horrible to work with since I have to click to open each options attributes to see them. I prefer working in tables where everything is visible and where I can create views to show the data in certain ways to make editing and understanding the logic in the backend much easier and faster.
I manage permissions at the page level rather than tab level, and I do use an option set for that. But yes, trying to manage conditions with a list of texts would be a mess - I definitely wouldn’t recommend that, but using a list of texts for tabs that don’t need conditions is much simpler than managing an option set for tabs and gives the dev greater flexibility.
Yes, parenting is good for nesting - although my main premise here is that it is much easier to manage and view via a table than hidden attributes - so when complexity grows enough to need attributes I often use a data table instead of option set. Another nice side benefit of using tables is that you can easily sort the rows alphabetically or numerically (another pet peeve of mine with option sets)
One app I work with has over 2000 option set values (it’s a huge and complex app). There’s no way I would try to manage that with option sets, but managing it with a data table is very intuitive and simple.
In this particular app I have a host of reuseable elements that are used with the data table option sets. There’s 5 different ways an option set can display to the user in the option card depending on the option set types icon type field.
I got tired of the client constantly asking to change option names etc so I built a way for the admin to change the options from the front end including changing name, description, adding icons, selecting colors, changing the option card style, parent etc. I also customize some labels based on the option type and I hold that in the data table. On the backend I can toggle on the features I want for the option types and then the admin gains access to those features on the front end.
Probably 80% of bubble apps will never need to convert option sets into data tables - I’m just sharing an alternative method for those that do. Not trying to say one is better than the other - both have their place and I use both in all apps I build.
bubble.io lack of built in object as a variable drives me insane, (weweb has it and its amazing), also lack of local storage and cache storage options. Also the lack of ability to preset list of data such as array of texts eg: ["text1", "text2"]
I believe you have access to the local storage. You just need to use a js script to access it, then on page load another script to extract data from it.
I know the quote was around the lack of built in object as a variable and local storage but there are plugins that allow for that. Plenty of local storage options available and a few I believe that work well with JSON and API Objects. My plugin Data Jedi has local storage and all functions and actions necessary to CRUD the API objects and use as object variables.
Definitely, and when Option Sets are used in a way that they are fit for purpose, the total size of Option Sets should not be large. If people are creating option sets with more than maybe 50-80 entries, they should use some of data type like custom data types or api objects. For me, I mainly use Option Sets for ease of use in dynamic expressions.
Really just kind of depends on the developers preference for ease of use. It is much easier to find in the option sets the specific ones needed if they are separate and not needed to open up the attributes to see which other ‘things’ they may be related to. For me over the years, experimenting with different approaches, option sets with too much reliance on attributes to differentiate them, is going to slow me down in development to have to open up each option to inspect attributes to try and track how all are working. For me, I’ve found it is easier to just use one option for the one purpose.
For options that would need to be user customize or admin customized, I use API Objects.
Definitely
API Objects would work better as can see all options as individual objects and see all fields for each, so can definitely store and manage much more easily. Can even add unique identifier keys for the option to make it even easier to pull out specific objects.
Tons of potential use cases for Options that have no need for any attribute.
For sure Bubble could have made the UI for Option Sets better, but it is the UI we are living with and likely will be for many years to come, so basically the massive disorganized list of tabs that are hard to manage without clear tabular view of attributes is describing how Option Sets are in Bubble.
Same here. Took a number of years of experience and experimentation for me to land at the simplest of solutions. KISS for option sets is a pretty good principle to try and live by. No need to try and over-engineer them much.
This doesn’t solve the issue but I generally create a colors (either hex or name for white labels) and an icons option set to start and then add those as attributes to all status and tabs option sets (in addition to sort, parent, admin >=, etc.)
For managing option sets that have more than 1 or 2 attributes, I generally create a tab for it on reusable that shows me options sets and their data/attributes and can have validation and filtering (albeit a little jenky). While it doesn’t allow for editing directly, one big pro of Option Sets is the ability to view them on one version and edit them on another (so don’t have to constantly refresh the page). Am I the only one who creates front end views of option sets?!?
Alternatively I’ll dump all the attributes into the display as well (and have a attribute for the “real” display or splitting the display by “ (“:first item ).