Sorting and Filtering - Bubble Limitation and workarounds

Hey all,

I’ve been building a CRM-style app in Bubble for a few months now, a call management tool with companies, campaigns, assignments, decision makers, and a queue system. As the app grew more complex I kept hitting the same set of walls. I’ve found workarounds for all of them but I genuinely don’t know if these are the best approaches, so I wanted to share what I do and ask the community if there’s something cleaner I’m missing.

You Can’t Sort a Search by a Related Type’s Field

This one hit me early. I have a Campaign Assignment data type. Each Assignment has a linked Company. I wanted to let users sort the Assignment list by Company revenue, Company employee count, or Company status.

Bubble’s search only lets you sort by fields on the type you’re searching. There is no “sort by Company’s revenue” operator when searching Assignments. It simply does not exist in the editor.

What the community often suggests:

Some people use client-side sorting with List Shifter or similar plugins. You fetch all records first and sort in the browser. This works for small datasets but falls apart the moment you need pagination. Once you have a few hundred assignments it becomes unusable.

Others try nested repeating groups, do a Search for Companies sorted by revenue, then render a nested RG of Assignments per Company. This technically produces a sorted visual result but is very hard to paginate, hard to style as a flat table, and gets slow quickly.

What I do:

I denormalize the sort fields. I add a company_revenue number field directly on the Assignment type, and a backend workflow fires every time a Company is saved:

Trigger: When Company is created or modified
Action: Search for Campaign Assignments where company = triggering Company
        Make changes to list:
          company_revenue = triggering Company's revenue
          company_employee_count = triggering Company's employee_count

Now I can sort Assignments by company_revenue natively.

The downside is obvious, you’re duplicating data. If the sync workflow breaks or a Company is updated through an edge case path, your denormalized fields go stale. I manage this with careful workflow coverage and a backfill recursive workflow for the initial data population.

Is there a better way? Is anyone doing this differently at scale? I’m particularly curious if there’s a Bubble-native approach I’m overlooking or a plugin that handles this cleanly without breaking pagination.

Summary of the problem and My Workarounds

Limitation My Workaround Concern
Can’t sort search by related type’s field Denormalize sort fields onto the searched type, sync via backend workflow Data duplication, sync coverage

It feels like there should have cleaner solutions. I’m shipping production apps with this workarounds and it hold up, but I’m always a bit uncomfortable knowing it rely on workflow discipline rather than a structural guarantee.

If you’ve solved this differently, especially at scale, I’d genuinely love to hear it. What am I missing?

For large apps, adding a text field has been my go to solution as well.

Another good solution has been to create an API connection to your app and pulling in data that way. Make a backend workflow that can pull the data you need via however you want to build the JSON. Which means you can pull in fields directly instead of relying on a new text field. It adds a bit more work but I found that it works very quick and ended up being a pretty good approach as well.

Hope that helps. :blush:

Great approach but doesn’t fit my case, my table is paginated. The in-memory sort requires loading all records first, which kills the point of pagination. Native search with a denormalized field keeps it fast and paginated out of the box. Still, let’s see if there is any other way! thanks @J805

There are no plugins that can hook into how Bubble handles queries. They will always load within search constraints, and then run their code

Your method and making API requests are the best native solutions.

Hey @ehsan.bubbledev.1 , Let me go a bit deeper since you clearly already know the denormalize/API options.

Your approach is actually the correct pattern. Even engineers on Postgres or MongoDB denormalize fields specifically to enable sorted queries on related types. Bubble just makes you feel dirty about it because there’s no migration system. The discomfort is understandable, but the pattern is solid.

To make the sync more bulletproof:

  • Add a company_last_synced_at timestamp on Assignment. Stamp it every time the sync runs, so you can query stale records (where last_synced_at < Company's Modified Date) and run targeted repairs instead of full table scans.
  • Run a nightly reconciliation workflow as a safety net for edge cases like bulk imports or API writes that bypass triggers.
  • Switch to “Schedule API Workflow on a List” for backfills if you’re still using recursive workflows — it’s faster and avoids recursion limits.

The one real alternative: If you keep adding denormalized fields as the app grows, a Xano or Supabase backend becomes worth considering. You’d use Bubble as the front-end only and get native JOIN queries with sorting on any related field. Big shift, but that’s the structural guarantee you’re after.

For now, your current approach with those safety nets is exactly what serious Bubble devs ship in production.

Your denormalization approach is exactly what I’ve landed on for the same problem. It’s not pretty but it’s the most reliable way to keep native Bubble pagination working.

One thing I’d add: I also run a scheduled recursive backend workflow as a “consistency check” that re-syncs the denormalized fields nightly. Catches any edge cases where the Company update didn’t trigger the Assignment sync correctly. Adds a safety net without relying purely on workflow discipline.

Haven’t found anything cleaner than this at scale — if anyone has, I’d love to hear it too.