Skip to content
Back to the Bootcamp
The Momentum Bubble Bootcamp, free. Part 6 of the paid course that trained hundreds of Bubble developers — released free, because the thinking it teaches is exactly what great AI-assisted development is built on.

Bootcamp

Updating data in Bubble: auto-binding vs workflows

Create and read get all the tutorial attention, but update is where an app earns its keep. Real records change constantly: a contact’s email is corrected, a status flips from hot to cold, a name gets its spelling fixed. Bubble gives you two very different ways to write those changes, and choosing between them is a design decision, not a matter of taste.

Auto-binding saves an input’s value the instant it changes, with no Save button and no workflow. Make changes to a thing is the workflow action that updates named fields on a specific record when you tell it to. One is immediate and per-field; the other is deliberate and transactional.

This walkthrough builds both into a CRM’s contact screen, along with two supporting moves that make the whole thing production-shaped: a redirect that guarantees default page values, and a delete flow with a confirmation step.

One page, four modes

First, the architecture. The CRM has a contacts page (plural) for the list and a contact page (singular) that serves every single-record job: new, view, edit and delete. One page, behaving as a small single-page app, switched by URL parameters.

Two decisions matter here:

  • Pass the record as a URL parameter, not as the page’s type of content. A page with a type of content demands a thing every time you visit it, which makes a “new contact” mode awkward, since there’s no contact yet to supply. A contact parameter carrying the record’s unique ID keeps every mode possible.
  • Add a mode parameter (view, create, edit) and let front-end conditionals show and hide sections based on it. You could formalise the mode values in an option set; either way, pick your names once and stick to them.

Wiring the list to the detail page is one workflow: make each row’s cell background clickable, and when it’s clicked, go to the contact page sending contact = This cell's Contact's unique id and mode = view.

On the contact page itself, read mode is built by duplication and conditionals:

  1. Duplicate the existing form wrapper and name the copies clearly: one wrapper for create/update, one for view.
  2. On the view wrapper, add a conditional: when Get mode from page URL is view, this element is visible. Give the create/update wrapper the inverse behaviour, and tick Collapse when hidden on both.
  3. Drive everything else off the same conditional: the breadcrumbs, the heading (showing Get contact from page URL's full name instead of “New contact details”), a 16 by 16 colour square whose background is the contact’s stored hex code, and the control buttons, edit and delete in view mode, save and cancel otherwise.
  4. Populate the read-only fields with Get data from page URL, typed as Contact: the contact’s email, phone, location and so on. The same expression pattern works for every field on the type.

The payoff of the mode parameter is that “what this page is right now” is stated in the address bar, and switching from viewing to editing is nothing more than rewriting mode=view to mode=edit.

Updating with Make changes to a thing

The workflow route has two halves you must always supply: which thing you’re updating, and which fields to set. Reference the thing via a search, a URL parameter or the current page’s thing; then list the field changes. Crucially, fields you don’t mention are not touched, so updating one field means mentioning exactly one field.

Before the save can work, edit mode needs a pre-filled form:

  1. Add a conditional to the form heading: when Get mode from page URL is edit, the text becomes “Edit contact details”.
  2. Set each input’s initial content to the corresponding field of the contact from the URL: first name, last name, email, phone, location. Copy the first dynamic expression and paste it into the rest, changing only the field. The picture uploader takes the contact’s photo as its dynamic image.
  3. You can chain a default onto any of these, so an empty field pre-fills with a fallback value, a handy trick for optional fields.

Now the save button gets two workflows guarded by Only when conditions: the existing Create a new contact runs only when Get mode from page URL is create, and a new Make changes to a thing runs only in edit mode.

Here’s the detail worth slowing down for. Bubble will happily let you reference the thing directly from the URL parameter, but that’s not the most secure way to do it. Instead, resolve the record with a search, so privacy rules control both the retrieval and the update:

  1. Set the thing to change to Search for Contacts with the constraint unique id = Get contact from page URL. The parameter is just text here, being compared against the unique ID Bubble stamps on every row.
  2. Append :first item. A search returns a list even when it can only ever match one record, and Bubble still needs telling to take the single item.
  3. Set the fields: First Name = Input First Name's value, Last Name = Input Last Name's value, Email = Input Email's value, and so on through the form. Since the form was pre-populated from the same record, saving unchanged fields writes back the same values harmlessly.

The original build hit a bug at exactly this point, and it’s instructive: the save appeared to do nothing. Running the debugger step by step showed both workflows’ conditions evaluating false, because the workflow checked for mode update while the URL said mode=edit. One inconsistent name, invisible until the debugger made it obvious. The habits that fix it are the lesson: keep your mode names consistent, and when something “doesn’t work”, step through it before assuming Bubble is broken. It’s usually your fault or mine.

Auto-binding: updates without a button

Now the other path. Auto-binding is demonstrated on the status dropdown that sits in each row of the contacts table, and the requirements are strict:

  1. The input’s parent group must have both a type of content and a data source. In a repeating group row, the cell’s group typed as Contact with the current cell’s contact as its source satisfies both. Check this first; auto-binding is not available without it.
  2. Configure the dropdown with dynamic choices: the contact status option set as the type, All Contact Status Option Sets as the source, and display as the option caption.
  3. Tick Enable auto-binding. Bubble asks which field to modify and offers only fields matching the dropdown’s type, so choose the status field.
  4. Bubble then warns that no privacy rule permits this, which is the important part. On the Data tab’s Privacy section, define a rule on Contact. Creating a named rule is also what exposes the “Everyone else” section, because until you define rules, the whole table is simply public. Then allow auto-binding on the status field.

Sit with what that grant means before moving on. The rule as configured lets every user, logged in or logged out, write that one field. That’s fine in a classroom build and reckless in production; auto-binding is enforced at the data layer, so the privacy rule is the security model, and it should be scoped to the users who genuinely need to edit.

With the rule in place, the experience sells itself: change a status from hot to cold, watch the thin progress bar run across the top of the page, check the database, and the row has changed. No button, no workflow, near real time, and it works on any input type, not just dropdowns.

So when does each approach fit? Auto-binding shines for quick single-field changes, especially inline across many rows, where a Save button per row would be absurd. Make changes to a thing is right for the form-shaped work: several fields committed together, validation before anything is written, and conditional logic around the save. The contact screen uses both, each where it belongs.

The default-value redirect trick

A small bug surfaced during the auto-binding build: loading the contacts page without its page parameter produced a phantom row and a stuck loading indicator, because logic on the page assumed a value that wasn’t there. The fix is a redirect that guarantees the default:

  1. Add a workflow: When page is loaded, only when Get page from page URL is empty.
  2. Action: Go to page contacts, ticking Send current page’s parameters and sending one more: page = 1.

The page quietly rewrites its own URL and everything downstream can rely on the parameter existing. The pattern generalises: whenever a page depends on a URL parameter, use a conditional self-redirect to guarantee a sane default rather than scattering is-empty checks through your expressions.

Deleting, carefully

Delete is the last letter in CRUD and mechanically the simplest: the Delete a thing action under Data, pointed at the record, in this case the contact from the page URL. That’s genuinely all there is to it, and that’s the problem. Data you want kept permanently shouldn’t vanish because someone’s click slipped.

So the delete button never deletes directly. It opens a confirmation popup that makes the user stop and be clear about what they’re doing: explicit wording about what’s being removed, and a confirm button in red, the semantic colour for danger. Confirm runs the delete; cancel closes the popup and returns to the contact untouched. Build the popup with the elements and conditionals you already know, and treat it as non-negotiable for any destructive action in any app you ship.

This skill in the AI era

The judgement in this build, not the clicks, is what transfers. Immediate-save versus transactional-save is the same decision you’ll make in any modern stack, resolving records through access-controlled queries instead of trusting URL input is a security instinct no tool supplies for you, and confirm-before-destroy is universal. Auto-binding enabled with a wide-open privacy rule is one of the most common findings in our Bubble rescue and migration work, precisely because the checkbox is easy and the thinking isn’t. Bring the thinking, and Claude Code will happily write the update paths to match; that division of labour is the story of moving from Bubble to AI-assisted development.

If this sparked something, let's talk.

No pitch, no pressure — just a conversation about what you're working on.

Let's talk
Share: