# How to optimize performance of Bubble.io apps: Step-by-Step Guide

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

## TL;DR

Slow Bubble apps lose users and waste Workload Units. This tutorial covers the most impactful performance optimizations: reducing database queries, replacing searches with Option Sets, optimizing Repeating Groups, minimizing page weight, and monitoring Workload Unit consumption. Apply these techniques to make your Bubble app noticeably faster without rebuilding anything from scratch.

## Overview: Optimizing Bubble App Performance

Performance is the most discussed pain point in the Bubble community. Apps become slow when database queries multiply, Repeating Groups load too many items, pages have too many dynamic elements, and plugins add unnecessary overhead. This tutorial gives you a practical optimization checklist covering database efficiency, workflow optimization, page weight reduction, and Workload Unit monitoring.

## Before you start

- A Bubble app that you want to optimize
- Access to Settings → Metrics for Workload Unit monitoring
- Basic understanding of Bubble's data architecture (searches, Data Types, Option Sets)
- Familiarity with Repeating Groups and how they load data

## Step-by-step guide

### 1. Audit your Workload Unit consumption

Go to Settings → Metrics (or the Logs tab → Workload metrics). Review the pie chart showing which activities consume the most WUs. Identify the top consumers — common culprits include complex searches, Repeating Groups with nested searches, and backend workflows processing large lists. Click into specific time periods to see spikes. The Server logs tab shows WUs charged per individual action, helping you pinpoint exactly which workflows and searches are most expensive. Focus your optimization efforts on the top 3-5 consumers first.

> Pro tip: Check WU consumption during peak usage hours — an app that seems fine with 10 users may struggle with 100.

**Expected result:** You have identified the top WU consumers and know which parts of your app to optimize first.

### 2. Replace searches with Option Sets where possible

Option Sets are cached on the user's device and cost zero Workload Units to access. Any data that is static and does not change per user — categories, statuses, countries, feature flags — should be an Option Set instead of a Data Type. Go to Data tab → Option sets and create sets for your static data. Then update all elements that currently search a Data Type for this static data to reference the Option Set instead. For example, replace 'Do a search for Categories' with 'All Categories' (the Option Set). This eliminates database queries entirely for that data.

**Expected result:** Static data is served from Option Sets with zero database cost, reducing WU consumption and improving load time.

### 3. Optimize Repeating Group performance

Repeating Groups are the most common performance bottleneck. Apply these fixes: (1) Add pagination — set a fixed number of rows (10-20) instead of showing all items. (2) Use database constraints instead of :filtered — constraints run on the server and use indexes; :filtered processes every row client-side. (3) Remove 'Do a search for' inside RG cells — each cell search multiplies queries by the number of visible cells. Instead, use Parent group's data references. (4) Pre-compute counts — if you show 'Number of comments' per post, add a Comment_Count field to the Post type and increment it in workflows instead of counting dynamically.

> Pro tip: A Repeating Group showing 20 items with 3 searches per cell generates 60 database queries on every load. Replacing those with Parent group references reduces it to 1 query total.

**Expected result:** Repeating Groups load faster with fewer database queries through pagination, constraints, and parent data references.

### 4. Reduce page weight and element count

Bubble renders every element when the page loads, even hidden ones. To reduce page weight: (1) Remove unused elements — check the Element Tree for elements you no longer need. (2) Move complex sections into Reusable Elements — they load on demand. (3) Uninstall unused plugins — every plugin adds JavaScript to every page regardless of use. Go to Plugins tab and remove any you are not actively using. (4) Compress images — use tools like TinyPNG before uploading. Bubble's image auto-compression helps but pre-compression is better. (5) Minimize the number of groups and nested containers — flatten your layout where possible.

**Expected result:** Pages load faster with fewer elements, no unused plugins, and optimized images.

### 5. Optimize workflows and backend processing

Move expensive operations to backend workflows where they do not block the user interface. Use 'Schedule API Workflow' to process heavy tasks asynchronously — the user sees a confirmation immediately while processing happens server-side. For bulk operations, use 'Schedule API Workflow on a list' instead of looping. Eliminate redundant workflow actions — if two actions write to the same record, combine them into one 'Make changes to a thing.' Remove 'Add a pause before next action' workarounds and use 'Result of step X' for data dependencies instead.

> Pro tip: For apps with significant performance challenges, RapidDev can conduct a full performance audit identifying the specific bottlenecks and implementing targeted optimizations to reduce WU consumption and improve load times.

**Expected result:** Expensive operations run asynchronously in backend workflows without blocking the user interface.

### 6. Implement caching strategies

Store frequently accessed data in Custom States or hidden floating groups to avoid repeated searches. On page load, run your heavy searches once and store results in a Custom State — subsequent references use the cached state instead of re-querying. For data that multiple users access (like a leaderboard), consider a CachedData Data Type that stores pre-computed results with a timestamp. A scheduled backend workflow refreshes this data periodically. Users read from the cached record instead of running the expensive query on every page load.

**Expected result:** Frequently accessed data is cached, reducing redundant database queries and improving response times.

## Complete code example

File: `Workflow summary`

```text
PERFORMANCE OPTIMIZATION — CHECKLIST
======================================

DATABASE OPTIMIZATION:
  [x] Replace static Data Type searches with Option Sets
  [x] Use constraints instead of :filtered on searches
  [x] Remove 'Do a search for' inside Repeating Group cells
  [x] Pre-compute counts/aggregates as fields (not dynamic)
  [x] Use 'Result of step X' instead of re-searching
  [x] Paginate Repeating Groups to 10-20 items

PAGE WEIGHT REDUCTION:
  [x] Remove unused elements from Design tab
  [x] Uninstall unused plugins from Plugins tab
  [x] Compress images before uploading (TinyPNG)
  [x] Move complex sections to Reusable Elements
  [x] Flatten nested groups where possible
  [x] Use Collapse when hidden on conditional elements

WORKFLOW OPTIMIZATION:
  [x] Move heavy processing to backend workflows
  [x] Use Schedule API Workflow on a list for bulk ops
  [x] Combine multiple writes to same record into one action
  [x] Remove unnecessary 'Pause before next action'
  [x] Use Custom Events for sequential dependencies

CACHING:
  [x] Store search results in Custom States on page load
  [x] Use hidden floating groups for frequently accessed data
  [x] Create CachedData records for shared expensive queries
  [x] Refresh caches with scheduled backend workflows

MONITORING:
  Settings → Metrics → Workload metrics
  - Review top WU consumers
  - Check peak usage periods
  - Monitor per-action WU costs in Server Logs
  - Set alert thresholds at 75% of plan limit
```

## Common mistakes

- **Using :filtered instead of database constraints on searches** — :filtered processes every row returned from the database individually on the client side. Constraints use server-side indexes and return only matching rows. Fix: Move filter logic into search constraints wherever possible. Only use :filtered for conditions that cannot be expressed as constraints.
- **Nesting 'Do a search for' inside Repeating Group cells** — Each cell runs its own database query. A 20-cell RG with one search per cell generates 20 queries per page load. Fix: Use Parent group's data references or pre-compute related data as fields on the parent Data Type.
- **Keeping unused plugins installed** — Every installed plugin loads its JavaScript on every page, adding to page load time even if the plugin is not used on that page. Fix: Go to Plugins tab and remove any plugins your app does not actively use.
- **Loading all items in a Repeating Group without pagination** — Bubble renders all items, not just visible ones. A list of 500 items creates 500 cells in the DOM, consuming memory and slowing rendering. Fix: Set a fixed number of rows (10-20) and add pagination controls or infinite scroll with incremental loading.

## Best practices

- Use Option Sets instead of database searches for all static data (categories, statuses, countries)
- Paginate Repeating Groups to 10-20 items and add load-more or pagination controls
- Use database constraints instead of :filtered for server-side filtering with indexes
- Remove unused plugins, elements, and workflows to reduce page weight
- Pre-compute counts and aggregates as fields instead of calculating dynamically
- Move heavy processing to scheduled backend workflows to keep the UI responsive
- Monitor Workload Unit consumption weekly and investigate any unexpected spikes
- Compress all images before uploading to reduce page load time

## Frequently asked questions

### What is the biggest performance killer in Bubble apps?

Nested searches inside Repeating Group cells. Each cell runs its own database query, multiplying queries by the number of visible cells. Replacing these with Parent group data references is the single highest-impact optimization.

### Do Option Sets consume Workload Units?

No. Option Sets are cached in the app's JavaScript on the client side. Accessing them costs zero WUs and is instant. Use them for all static data.

### How do I know if my app is slow because of the database or the page?

Check Server Logs for query execution times (database) and use your browser's DevTools Network tab for page load times (frontend). High WU consumption points to database issues; slow page rendering points to too many elements or heavy plugins.

### Will upgrading my Bubble plan make my app faster?

Higher plans provide more server capacity, which helps under load. But if your app has inefficient queries or heavy pages, upgrading only masks the problem temporarily. Optimize first, then scale.

### Can I use an external database for better performance?

Yes, but external databases add latency because calls route through Bubble's server (5 hops instead of 3). External databases help when you need advanced SQL queries or handle millions of records.

### Can RapidDev help optimize my Bubble app's performance?

Yes. RapidDev offers performance audits that identify specific bottlenecks in your app's database queries, page rendering, and workflow efficiency, then implements targeted optimizations to reduce WU costs and improve speed.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/optimize-performance-of-bubble-apps
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/optimize-performance-of-bubble-apps
