# How to work with dynamic data types in a Bubble.io app: Step-by-Step Guide

- Tool: Bubble
- Difficulty: Beginner
- Time required: 15-20 min
- Compatibility: All Bubble plans
- Last updated: March 2026

## TL;DR

Bubble's data model uses custom Data Types (tables) with Fields (columns) and Things (rows). You create relationships by setting a field's type to another Data Type, supporting one-to-one, one-to-many (list field), and many-to-many patterns. Understanding how to structure types, reference related data in expressions, and use Privacy Rules is essential for every Bubble app.

## Work with Dynamic Data Types in Bubble

This tutorial explains Bubble's data model — how to create types, define relationships, and use them throughout your app. Understanding data types is foundational to building any Bubble application.

## Before you start

- A Bubble account with an active app
- Basic understanding of databases (tables, rows, columns concept)
- Familiarity with the Bubble editor

## Step-by-step guide

### 1. Create Custom Data Types

Go to Data tab → Data types → click 'New type'. Name it descriptively (e.g., 'Project'). Add fields: name (text), description (text), status (text), due_date (date), budget (number), is_active (yes/no). Each field has a type: text, number, date, yes/no, file, image, geographic address, or another Data Type. Check 'This field is a list' for fields that hold multiple values.

**Expected result:** A new Data Type exists with multiple fields of different types.

### 2. Set Up Relationships Between Types

Relationships connect Data Types. One-to-one: add a field 'manager' of type User on Project — each project has one manager. One-to-many: add a field 'team_members' of type User as a list on Project — each project has many members. Many-to-many: create a join type 'ProjectMembership' with fields project (Project) and member (User). Choose the pattern based on your needs.

> Pro tip: For one-to-many with under 100 items, list fields work well. For larger relationships or when you need metadata on the relationship, use a join Data Type.

**Expected result:** Data Types are linked through relationship fields.

### 3. Reference Related Data in Expressions

In the Design tab, you can chain references through relationships. For example: 'Current Page Project's manager's email' traverses from Project → User → email. In a Repeating Group of Projects, each cell can show 'Current cell's Project's team_members:count' for the team size. Use ':first item', ':last item', and ':each item's [field]' operators to work with list fields.

**Expected result:** Dynamic expressions traverse relationships to display related data.

### 4. Search and Filter by Related Data

Use 'Do a Search for' with constraints on related fields. Example: Search for Projects where manager = Current User returns projects managed by the logged-in user. For list fields, use 'contains' as the constraint type: Search for Projects where team_members contains Current User. Combine multiple constraints for complex filters.

**Expected result:** Searches filter data based on relationships between types.

### 5. Set Privacy Rules for Each Data Type

Go to Data tab → Privacy. For each Data Type, create rules controlling who can find and view records. Example: for Project, add a rule 'When Current User is in This Project's team_members' with permissions to Find in searches and View all fields. This ensures users only see projects they belong to.

**Expected result:** Privacy Rules restrict data access based on user relationships.

## Complete code example

File: `Workflow summary`

```text
DATA ARCHITECTURE EXAMPLE: Project Management App

DATA TYPES:
- User (built-in)
  - name (text)
  - role (text)
  - avatar (image)

- Project
  - name (text)
  - description (text)
  - status (text: active/completed/archived)
  - manager (User) — one-to-one
  - team_members (list of Users) — one-to-many
  - created_date (date)
  - due_date (date)

- Task
  - project (Project) — many-to-one
  - title (text)
  - assignee (User) — one-to-one
  - status (text: todo/in-progress/done)
  - priority (number)
  - due_date (date)

- Comment
  - task (Task) — many-to-one
  - author (User)
  - content (text)
  - created_date (date)

RELATIONSHIP PATTERNS:
- Project → User (manager): one-to-one
- Project → User (team_members): one-to-many via list
- Project → Task: one-to-many (Task has 'project' field)
- Task → Comment: one-to-many (Comment has 'task' field)
- Task → User (assignee): one-to-one

EXPRESSION EXAMPLES:
- Current Page Project's manager's name
- Current Page Project's team_members:count
- Search for Tasks (project = Current Page Project):each item's status
- Current cell's Task's project's name
```

## Common mistakes

- **Using text fields for relationships instead of Data Type references** — Text fields cannot traverse relationships. You would need to search by text match instead of direct reference, which is slower and error-prone. Fix: Always use a field typed as another Data Type for relationships, not text fields storing IDs or names.
- **Creating deeply nested relationships (4+ levels)** — Chaining references through 4+ types (A's B's C's D's field) becomes slow and hard to maintain. Fix: Flatten your data model by adding direct references where needed, or denormalize by copying frequently accessed data.
- **Not setting Privacy Rules on new Data Types** — Without Privacy Rules, all data is accessible to all users by default, creating security vulnerabilities. Fix: Create Privacy Rules immediately after creating a new Data Type.

## Best practices

- Name Data Types as singular nouns (Project, not Projects) for clarity in expressions.
- Use list fields for small collections (under 100 items) and separate join types for larger relationships.
- Add Privacy Rules to every Data Type immediately after creation.
- Use Option Sets for static categories instead of Data Types for better performance.
- Document your data model — Bubble has no built-in schema diagram, so maintain one externally.
- Avoid circular references (A references B which references A) as they complicate Privacy Rules.

## Frequently asked questions

### What is the difference between a Data Type and an Option Set?

Data Types store dynamic, user-generated data in the database. Option Sets store static, developer-defined data in the app source code. Use Option Sets for categories, statuses, and labels that do not change. Use Data Types for user content.

### Can I change a field's type after creating it?

No. You must delete the field and create a new one with the correct type. Deleting a field does not remove the underlying data immediately, but you lose access to it in the editor.

### How many Data Types can I create?

Bubble supports up to 1,000 custom Data Types per app. Most apps use 10-30 types.

### What happens when I delete a Data Type?

All records of that type are deleted. Any elements, workflows, or expressions referencing it will break. The Issue Checker will flag these broken references.

### How do I handle many-to-many relationships?

Create a join Data Type. For example, ProjectMembership with fields 'project' (Project) and 'user' (User). Search for ProjectMemberships to find all users in a project or all projects for a user.

### Should I denormalize data for performance?

Sometimes. Storing frequently accessed computed values (like task count on Project) avoids expensive searches. For complex data modeling, RapidDev can help design an optimized schema for your use case.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/work-dynamic-data-types-bubble-app
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/work-dynamic-data-types-bubble-app
