Style guide

Data and workflow naming conventions

Use names to make the app searchable

Naming conventions are mostly about search and handoff.

If another developer cannot quickly find the backend workflow, field, reusable element, custom event, or option set they need, the app is harder to maintain. Bubble does not give you the same file structure and type navigation you get in code, so names carry more weight.

A backend workflow called send_welcome_email is better than new_user. A reusable element called Header Dashboard is better than Group Header if the app has several headers. A data type called Subscription Invoice is better than Invoice if the app also has Stripe invoices, internal invoices, or supplier invoices.

The exact convention matters less than having one. I would rather take a slightly ugly convention used everywhere than a theoretically nice convention used in half the app.

Signal the type where it helps

Names should help you see what type of value you are dealing with in the Bubble editor.

For primitive fields, we generally like compact names:

  • isArchived for a yes/no field

  • stripeCustomerId for a text field

  • sortOrder for a number field

  • archivedAt for a date field

For richer Bubble objects, Title Case is usually easier to scan:

  • Project Member for a data type

  • Subscription Plan for an option set or data type

  • Order Status for an option set

The reason for this is simple. When you see Current User's isAdmin is yes, you know you are reading a yes/no field. When you see Current User's Role, you are probably reading an option set or linked data type.

If an app already has a clear field naming convention, follow that. The important bit is that fields, option sets, data types, custom states, reusable properties, and workflow parameters do not all blur together.

Do not add option set prefixes by default

I generally would not prefix every option set with OS, Option Set, or similar.

In most apps, User Role is easier to read than OS User Role. Order Status is easier to read than Option Set Order Status. Bubble's expression editor usually gives enough context, and the app's data model should make the type obvious.

Use a prefix only when it removes a real ambiguity. If you have a data type called Plan and an option set called Plan, fix the naming. That might mean Subscription Plan for the option set and Plan Feature for the data type, or it might mean a prefix if the app already uses that convention.

The same applies to option values. In an Order Status option set, use Draft, Awaiting Payment, Confirmed, and Cancelled. Do not write Order Status - Draft unless the repeated label helps in a specific expression or admin view.

Use option sets for product constants

Option sets are good for values defined by the app, not records users manage as source-of-truth data.

Good option-set candidates:

  • user roles

  • order statuses

  • subscription plan types

  • fixed page tabs

  • permission groups

  • supported countries, if the list is controlled by the product

Use a data type when users or admins need to create, edit, archive, permission, search, audit, or report on the records.

For example, Order Status is probably an option set. Product Category might be an option set in a small marketplace where the categories are fixed. It should probably be a data type if the client needs an admin page to add categories, reorder them, translate them, or report on them.

Option sets also do not need to be duplicated for every page. If a single-page app has separate tab option sets for Dashboard Tabs, Settings Tabs, and Billing Tabs, check whether one Tab option set with a Pages attribute would be cleaner. Each tab can say which pages it belongs to, and the page can filter the tabs it displays.

The same pattern works for statuses. You might have one Status option set and a Status Type attribute rather than separate option sets for order statuses and shipment statuses. Draft, Completed, and Cancelled can apply to both. Out For Delivery can apply only to shipments.

Do not force this if the concepts behave differently. Similar names are not enough. The options should share enough behaviour that one option set makes the app clearer.

Name backend workflows by how they run

Backend workflow names should make the trigger obvious.

There is a specific Bubble gotcha here: database trigger names can conflict with backend workflow endpoint names. If you have a database trigger called invoice and a backend workflow endpoint also called invoice, calling the endpoint may return a workflow-not-found style error while the trigger still runs.

So avoid generic backend names like invoice, customer, or subscription when the app has webhooks, database triggers, backend custom events, and scheduled workflows around the same thing.

Use names like:

  • endpoint_stripe_invoice_created for a backend workflow called by Stripe or the API Connector

  • trigger_invoice_updated for a database trigger

  • event_sync_invoice_status for a backend custom event

  • task_send_trial_expiry_reminders for a scheduled backend workflow

You do not need these exact prefixes. You do need a convention that lets a developer tell whether the workflow is an endpoint, database trigger, custom event, or scheduled task before opening it.

This matters most around payments and integrations. Stripe apps often have workflows for invoice, customer, subscription, payment, and checkout. Plain nouns are too easy to collide and too vague to debug.

Keep external endpoint names stable

Be careful renaming public backend workflows.

If a Stripe webhook, API Connector call, external service, or another Bubble app calls the endpoint URL, changing the endpoint name can break the caller. Rename internal custom events freely if it makes the app clearer. Rename public endpoints only when you can update and test every caller.

For existing apps, I would usually clean up names in this order:

  • backend workflows with vague or conflicting names

  • data types and option sets that are hard to search

  • reusable elements with generic names like Group Main

  • custom states and reusable properties that hide their type

Do not rename everything for tidiness. Rename things that slow down debugging, confuse handoff, or make Bubble expressions harder to read.

Rule of thumb

Use the shortest name that tells another developer what the Bubble thing is and why it exists.

For fields, signal the value type where useful. For option sets, avoid arbitrary prefixes unless they remove confusion. For backend workflows, include whether the workflow is an endpoint, trigger, custom event, or scheduled task.

Was this helpful?