Skip to main content
RapidDev - Software Development Agency
bubble-tutorial

How to structure the database in Bubble

Structuring your Bubble database correctly from the start prevents performance issues, simplifies workflows, and reduces workload unit consumption. This tutorial covers database design principles adapted for Bubble's architecture, including when to normalize versus denormalize, how to model one-to-many and many-to-many relationships, when to use Option Sets instead of Data Types, and common schema patterns for SaaS apps and marketplaces.

What you'll learn

  • How to design efficient Data Type relationships in Bubble
  • When to normalize versus denormalize your database schema
  • How to model one-to-many and many-to-many relationships
  • Common database patterns for SaaS, marketplace, and social apps
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate7 min read25-30 minAll Bubble plansMarch 2026RapidDev Engineering Team
TL;DR

Structuring your Bubble database correctly from the start prevents performance issues, simplifies workflows, and reduces workload unit consumption. This tutorial covers database design principles adapted for Bubble's architecture, including when to normalize versus denormalize, how to model one-to-many and many-to-many relationships, when to use Option Sets instead of Data Types, and common schema patterns for SaaS apps and marketplaces.

Overview: Structuring the Database in Bubble

This tutorial teaches you database design best practices specifically for Bubble. Unlike traditional SQL databases, Bubble's database has unique characteristics — real-time search updates, workload unit costs per query, and field-level privacy rules. You will learn patterns that work with these characteristics rather than against them.

Prerequisites

  • A Bubble app (new or existing)
  • Basic understanding of what Data Types and fields are in Bubble
  • A concept of the app you want to build (even a rough idea)

Step-by-step guide

1

Understand Bubble's database fundamentals

Bubble's database runs on PostgreSQL. A Data Type is a table, a Thing is a row, and a Field is a column. Every record automatically gets: Unique ID (32-character, immutable), Created Date, Modified Date, and Slug. The User Data Type is auto-created with email and password handling. You can have up to 1,000 custom Data Types. Key differences from traditional databases: searches auto-update in real-time on page elements, text search indexes only the first 256 characters, and the database processes approximately 100 rows per second. Deleting a field leaves the underlying data in the database.

Expected result: You understand Bubble's database architecture and its unique characteristics that affect schema design.

2

Design relationships between Data Types

In Bubble, relationships are created by adding a field of another Data Type. One-to-many: add a field of the parent type on the child. Example: a Task has a project field (type: Project) — each task belongs to one project, but a project has many tasks. To find all tasks for a project, search Tasks where project = the specific Project. Many-to-many: add a list field. Example: a Course has a students field (list of Users) or a Student has an enrolled_courses field (list of Courses). For large many-to-many relationships, create a junction Data Type (Enrollment with student and course fields) to avoid list size limits and enable extra metadata.

Pro tip: Bubble list fields have a practical limit of about 10,000 items. For relationships that could exceed this, always use a junction Data Type instead of a list field.

Expected result: You can model one-to-many and many-to-many relationships using Bubble's field types and junction Data Types.

3

Decide when to denormalize for performance

In traditional databases, normalization avoids data duplication. In Bubble, selective denormalization improves performance dramatically. Example: instead of searching Reviews and calculating average_rating on every profile page load (expensive), store average_rating as a field on the User record and update it when a new review is created. Other denormalization candidates: item counts (store comment_count on Post instead of counting with a search), computed totals (store order_total instead of summing line items), and latest values (store last_activity_date instead of searching for the most recent event).

Expected result: You know when to store computed values as fields to avoid expensive searches.

4

Choose between Data Types and Option Sets

Option Sets are static, developer-managed lists stored as part of your app's code — they load instantly with zero workload unit cost. Data Types are dynamic database tables with privacy rules, user-generated content, and search capabilities. Use Option Sets for: statuses (Active, Inactive, Pending), categories (Electronics, Clothing, Food), roles (Admin, Member, Viewer), countries, colors, and any list that does not change per user. Use Data Types for: user-generated content, records that need privacy rules, data that users create/edit/delete, and anything requiring relationships to other database records.

Expected result: You can identify which data belongs in Option Sets versus Data Types for optimal performance.

5

Apply common schema patterns

SaaS pattern: User → Organization (many-to-many via Membership junction with role field) → Project → Task. Store the user's current_organization on User for quick access. Marketplace pattern: User with role (Buyer/Seller), Product → Order → OrderItem (junction between Order and Product with quantity and price). Social pattern: User → Post → Comment, Following (junction between two Users: follower and followed), Like (junction between User and Post). For all patterns, add created_by (User) and created_date fields on every Data Type for audit tracking.

Pro tip: Draw your schema on paper before building. Each box is a Data Type, each line is a field reference. This 5-minute exercise saves hours of restructuring later.

Expected result: You have a well-structured database schema following proven patterns for your app type.

Complete working example

Workflow summary
1DATABASE DESIGN PATTERNS FOR BUBBLE
2=====================================
3
4RULES OF THUMB:
5 1. Option Sets for static lists (zero WU cost)
6 2. Denormalize computed values (counts, averages, totals)
7 3. Junction Data Types for large many-to-many relationships
8 4. created_by and created_date on every Data Type
9 5. Maximum 1,000 custom Data Types per app
10 6. List fields: practical limit ~10,000 items
11
12SAAS PATTERN:
13 User:
14 - current_organization: Organization
15 Organization:
16 - name, logo, plan (Option Set)
17 Membership (junction):
18 - user: User, organization: Organization
19 - role: Option Set (Admin/Member/Viewer)
20 Project:
21 - organization: Organization, name, status (Option Set)
22 Task:
23 - project: Project, title, assigned_to: User
24 - status: Option Set, due_date, completed: yes/no
25
26MARKETPLACE PATTERN:
27 User:
28 - role: Option Set (Buyer/Seller)
29 Product:
30 - seller: User, title, price, category (Option Set)
31 Order:
32 - buyer: User, total: number, status: Option Set
33 OrderItem (junction):
34 - order: Order, product: Product
35 - quantity: number, unit_price: number
36
37SOCIAL PATTERN:
38 User:
39 - followers_count: number, following_count: number
40 Post:
41 - author: User, content, like_count: number
42 Comment:
43 - post: Post, author: User, body
44 Following (junction):
45 - follower: User, followed: User
46 Like (junction):
47 - user: User, post: Post
48
49DENORMALIZATION EXAMPLES:
50 Instead of: Search Reviews :average rating (every page load)
51 Store: User's average_rating field (update on new review)
52
53 Instead of: Search Comments :count (every post display)
54 Store: Post's comment_count field (increment on new comment)

Common mistakes when structuring the database in Bubble

Why it's a problem: Using Data Types for static lists like statuses and categories

How to avoid: Convert static Data Types to Option Sets. Use Data Types only for dynamic, user-generated, or privacy-controlled data.

Why it's a problem: Using list fields for large many-to-many relationships

How to avoid: Create a junction Data Type for many-to-many relationships that could grow large (e.g., Enrollment instead of Course's students list)

Why it's a problem: Calculating aggregates like counts and averages on every page load

How to avoid: Store computed values as denormalized fields and update them when the source data changes

Best practices

  • Use Option Sets for any data that is static and developer-managed
  • Denormalize computed values like counts, averages, and totals as fields
  • Use junction Data Types instead of list fields for large many-to-many relationships
  • Add created_by (User) and created_date fields to every Data Type for audit tracking
  • Draw your schema on paper before building in Bubble
  • Limit list fields to relationships that will stay under a few hundred items
  • Use the 'Result of step X' operator to reference newly created records in workflows

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I am building a [describe your app] in Bubble.io. Help me design the database schema. What Data Types, fields, and relationships should I create? When should I use Option Sets vs Data Types? Where should I denormalize for performance?

Bubble Prompt

Create a SaaS database schema with Users who belong to Organizations through a Membership junction table. Add Project and Task Data Types linked to the Organization. Use Option Sets for statuses and roles. Include denormalized fields for task counts and completion percentages.

Frequently asked questions

How many Data Types can I have in a Bubble app?

Up to 1,000 custom Data Types. Most apps need 10-30 Data Types. If you are approaching this limit, consider consolidating similar types.

Should I normalize or denormalize my Bubble database?

Use selective denormalization. Keep the core structure normalized for data integrity, but store computed values (counts, averages, totals) as fields to avoid expensive searches on every page load.

What is the difference between a list field and a junction Data Type?

A list field stores references directly on the record (simpler but limited to ~10K items). A junction Data Type is a separate record linking two types (scalable and allows extra metadata like role or date).

Can I change my database structure after building the app?

Yes, but with caution. Adding fields is easy. Deleting fields leaves orphan data. Restructuring relationships requires updating all references in workflows, pages, and privacy rules.

Can RapidDev help design my Bubble database schema?

Yes. RapidDev can design optimized database schemas for any app type, including proper relationships, denormalization strategy, Option Set planning, and privacy rule architecture.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.