A question in the Quickbase community described a problem a lot of older apps run into the day someone asks for mobile access (original thread here). The app had a legacy form with more than 230 form rules. On desktop it worked. In the mobile app it fell apart:
- Records were saved with mandatory fields blank.
- Popup messages appeared after every field the user filled in, instead of once.
- Error messages written in HTML didn't show up on mobile.
- Rules fired on save that had nothing to do with what the user changed.
The asker had looked at the newer forms but ran into two walls: a 100-rule limit, and the new form not appearing in the mobile form dropdown (it was still in beta at the time).
Both of those have moved on since then, and the fix is less about squeezing 230 rules into a new form and more about moving each rule to the right place. Here's how I'd do the migration, step by step.
The short version
- Move the "must have" checks (required fields, "required when Status is X", "can't save if...") out of form rules and into custom data rules on the table.
- Rebuild the form as a new form. New forms became generally available in the Quickbase mobile app on April 21, 2025 (app version 1.68), and form rules in them behave the same on mobile as on desktop.
- Assign the new form on the table's Forms page, in the View/Edit/Add Form (Mobile) column.
Once validation lives on the table, the form only needs rules for things like showing and hiding sections or filling in values, and that list is usually a lot shorter than 100.
Why legacy rules don't protect your data on mobile
A form rule belongs to one form. It runs when someone uses that form, and nowhere else. Any save that doesn't go through that exact form skips it: a different form, grid edit, an import, a pipeline, an API call. If the mobile app is showing a form your rules don't run on (or don't run the same way on), the "required" check never happens and the record saves with blanks.
To see it for myself, I made a small Work Orders table in a sandbox app with Status, Completion Notes and Completed Date fields, and added a few records through the API, including one marked Complete with no notes and no date. Every one of them saved. Nothing at the table level said those fields mattered.
Custom data rules are different. They belong to the table. Quickbase's help on custom data rules lists where they're applied:
- Adding or editing records using a form or the API
- Grid edit (only new or changed rows are checked)
- Importing records
- Pipelines (the error shows on the pipeline)
- Moving cards on a Kanban report or events on a calendar report
- Refreshing a connected table
The mobile app saves through the same table, so the rule applies there too. That's why the first step is to move validation, and it's worth doing even before you touch the form.
Step 1: Sort your existing rules into buckets
With 230 rules, don't start rebuilding. Start with a list. Open the legacy form's rules and put each one in one of these groups (a spreadsheet works fine):
| What the rule does | Where it should live |
|---|---|
| Makes a field required, always or under a condition | Custom data rule |
| Blocks a save or shows an error when data is wrong | Custom data rule |
| Shows or hides fields or sections | New form rule (Show / Hide) |
| Makes fields read-only | New form rule (Make read-only), or field permissions by role if it's about who may edit |
| Sets a value (a timestamp, a default, a copied value) | New form rule (Change value), or a formula field or pipeline if it has to happen no matter where the record is saved |
| Shows a helpful note while someone fills in the form | New form rule (Display message), used sparingly |
| Nobody remembers why it's there | Turn it off and see who complains in testing |
Two things usually come out of this exercise:
- A big share of the rules are validation. On older forms, a "required when" check is often written as several rules: one to show a message, one to block the save, one to undo something. On the table it becomes one line in one formula.
- Many rules are duplicates. Ten rules that each hide the same section for a different status can usually be one rule with an "or" condition.
Step 2: Write the custom data rules
Custom data rules are set per table:
- Open the table and go to Settings.
- Choose Advanced settings.
- Find the custom data rules section, turn custom data rules on, and enter the formula.
- Save.
The rule is a normal Quickbase formula. If the record is fine, it returns nothing. If it isn't, it returns text, and that text becomes the error message. Messages must be text in quotes.
Here's the rule from my Work Orders example. Completion Notes and Completed Date are only required once the work order is marked Complete:
If(
[Status] = "Complete" and Trim([Completion Notes]) = "",
"Completion Notes are required when Status is Complete.",
[Status] = "Complete" and IsNull([Completed Date]),
"Enter the Completed Date before marking this work order Complete."
)
If() can take several condition and message pairs. It returns the first one that matches, so the user fixes one problem at a time.
Before turning the rule on, I pasted the same formula into a formula text field on the sandbox table so I could see what it returns for each record. The results:
| Work order | Technician | Status | Completion Notes | Completed Date | Rule result |
|---|---|---|---|---|---|
| Replace lobby light fixtures | Sarah Lee | Complete | (blank) | 11-03-2026 | Completion Notes are required when Status is Complete. |
| Fix loading dock door | Mike Chen | Complete | (only spaces) | 11-02-2026 | Completion Notes are required when Status is Complete. |
| HVAC filter swap | Ana Torres | Complete | Swapped all 12 filters | (blank) | Enter the Completed Date before marking this work order Complete. |
| Patch drywall in room 204 | Sarah Lee | Complete | Patched and painted | 11-03-2026 | (nothing, saves) |
| Inspect roof drains | Mike Chen | In Progress | (blank) | (blank) | (nothing, saves) |
That's what you want: drafts and in-progress records still save with gaps, and only a "Complete" record has to be finished. Once the rule is on, a save that would produce one of those messages is rejected and the message is shown to the user. That holds for a form save on desktop or in the mobile app, a grid edit, an import or an API call. For an API call or pipeline, the message comes back in the error response instead of on a form.
Testing in a formula field first is a habit worth keeping. It shows you exactly which existing records would fail before anyone gets blocked.
Use Trim() for text fields
Note the Trim([Completion Notes]) = "" check. In my sandbox, IsNull([Completion Notes]) came back false for the blank records, because an empty text field holds empty text rather than null. Comparing the trimmed value to "" catches both a truly blank field and one with only spaces (the "Fix loading dock door" row above). For date fields, IsNull() works as expected. For numeric fields, watch out for the "treat blank as zero" setting, which makes a blank number read as 0 in formulas.
Listing every problem at once
By default a rule returns one message per record. If you'd rather tell the user everything that's missing in one go, build the message with variables:
var bool done = [Status] = "Complete";
var text notes = If($done and Trim([Completion Notes]) = "",
"Completion Notes are required when Status is Complete. ");
var text dt = If($done and IsNull([Completed Date]),
"Enter the Completed Date before marking this work order Complete.");
Trim($notes & $dt)
On a record marked Complete with neither field filled in, this returned both sentences together. On a finished record it returned nothing.
Keep the messages plain text
The asker's HTML error messages didn't show on mobile. I'd write data rule messages as plain sentences that say what's missing and what to do. The same message can end up on a desktop form, in the mobile app, in a pipeline's error or in an API response, and plain text reads fine in all of them.
A few things to know before you turn rules on
From Quickbase's help on custom data rules:
- Rules only check records being added or changed. Existing records that already break a rule aren't touched, but the next edit to them has to pass.
- Data rule errors come after the built-in errors (required, unique, max length). If a save already fails one of those, users see that first.
- Rules that only use fields on the same table behave predictably. Rules that depend on lookup or summary fields can act up, especially with editable embedded reports on the form.
- Because rules also apply to imports and pipelines, check whether any import or pipeline writes records that would now fail. Fix those first, or you'll find out from a failed run.
Step 3: Build the new form
There's no one-click conversion from a legacy form to a new form, so build it fresh with the old one open next to it:
- Go to the table's Settings.
- Next to Forms, use + New to create a form. It opens the form builder with one section and one column.
- Add fields with Click to add here, and organize them into sections and, if it helps, pages shown as tabs or steps. On a phone, columns stack on top of each other, so long forms are easier to use when they're split into sections or steps.
- Open Form rules from the builder's page bar and add only the rules from the "form" buckets in Step 1: show/hide, read-only, change value, labels, and the occasional display message.
- Save the form.
New forms are limited to 100 rules per form. After moving validation to the table and combining duplicates, most forms come in well under that. If you're still over, look for rules that can be merged with "any of these conditions" and for sections you can show or hide as a whole instead of field by field.
A couple of notes on the form rules builder:
- Each rule has a "When" (conditions) and a "Then" (actions). The "Otherwise" side is filled in for you as the reverse of the actions, so a single "show this section when..." rule also hides it when the condition is false. You don't need a second rule for the opposite case.
- Rules run top to bottom. If two rules act on the same field, the one higher in the list runs first.
- The builder has Require and Prevent save actions. They're fine for making the form friendlier, but they're still form-only. The custom data rule is the one that actually protects the data.
Step 4: Assign the new form for mobile
On the table's Forms page, find Set how different roles use these forms:
- In the View/Edit/Add Form (Mobile) column, pick the new form for each role that uses the mobile app.
- Alternatively, assign the new form as the desktop Add, Edit and View form and set mobile to use the full site forms. Then desktop and mobile users get the same form.
If you have report-specific form settings, check the Override role settings by report section as well. It has its own Mobile column.
One gotcha from the April 2025 release notes: if a role has a legacy form specifically assigned for mobile, it keeps getting that legacy form. Nothing switches over until you change that column.
Step 5: Test on a phone before rolling it out
Use a test record and a test user in each role. Something like:
- On the phone, open a work order, set Status to Complete and leave Completion Notes blank. Save. The save should be blocked with your message, shown once.
- Fill in the notes and the date and save again. It should go through.
- Check that the sections you expect to appear and disappear do so as you change Status, and that no messages pop up while you're just filling in fields.
- On desktop, try the same thing in grid edit. It should be blocked too.
- If you have imports or pipelines writing to the table, run one with a test record that breaks the rule, and confirm the error comes back the way you expect.
Why this also fixes the popups
The repeated popups most likely come from form rules re-evaluating as the user changed fields. A rule with a "display message" action fires whenever its condition becomes true, and on a long form with a lot of rules that can mean a message after nearly every field.
A custom data rule doesn't run while someone is typing. It runs once, at save, and either lets the record through or returns its message. So the "you forgot X" messages move from "every time you touch a field" to "once, when you try to save," which is what the asker wanted in the first place.
Summary
- Legacy form rules only run on that form. Anything that must always be true belongs in a custom data rule on the table (Settings > Advanced settings), which applies to forms on desktop and mobile, grid edit, imports, pipelines and the API.
- Write the rule as an
If()that returns a plain-text message when something's wrong. UseTrim([Field]) = ""for text fields, and test the formula in a formula field before turning it on. - Rebuild the form as a new form, keeping only show/hide, read-only, value and label rules. New forms allow up to 100 rules per form.
- Assign it in the View/Edit/Add Form (Mobile) column on the table's Forms page, or use the same new form for desktop and set mobile to use the full site forms.
- Test on a phone with a record that breaks the rule. You should see one clear message at save, and no more blank mandatory fields.