1. Wrong operator names

and, or, neq, nin and == are rejected when you save. Use all, any, ne, not_in, eq.

2. Trusting what users can edit

  • Compare values: $auth.claims.plan equals pro
is safe only if plan is set by your server. A person can edit user_metadata. Use roles, permissions or private metadata (app_metadata), and mark attributes that grant things admin-only.

3. Null equals null

  • Compare values: $record.org equals $auth.org
When both are missing, this is true. Everyone without an organization sees every record without one. Add $auth.org is set.

4. Forgetting the owner on server-created records

A secret-key create with no owner leaves owner_id empty. The owner rule never matches, so the person can’t see their own record. Set it explicitly.

5. A write left on “default”

An enabled action with no rule allows any signed-in user. Studio warns in amber. Choose a rule for every action you turn on.

6. public on a write

Studio flags it in red: “Anyone on the internet… can add records.” Only a signup or contact form should be public, and then rate-limited.

7. list looser than get (or the other way)

People read records they can’t list by guessing ids, or see rows they can’t open. Use the same rule for both.

8. Protecting the UI instead of the data

is presentation. If the delete rule is authenticated, anyone can call it. The rule is the lock.

9. A route that skips the owner check

A route with permission:orders.pay doesn’t know the order is yours. The flow must load the order as the caller and check, or let the table’s rules do it (Routes).

10. Relying on a hidden column

A rule doesn’t hide columns. Anyone who can read the row can read all its columns (except write-only ones). Split the table or use write-only for secrets.

11. Rules that depend on other tables

JSON can’t query another table. People write rules that assume it can. Copy the needed value onto the record, put it in the token, or check it in a flow. See Rules that need more data.

12. Changing a shared named rule without testing

One edit changes every table that uses it. Test, or fork the rule first (Named rules).

13. Expecting roles to apply instantly

Roles live in the token. A change arrives at the next refresh (minutes) or sign-in. End sessions to force it.

14. Testing only as yourself

Your own account is the most permitted one. Test as a stranger, as a different team’s member, and as a visitor.

15. Using not around missing data

None of ($record.status equals archived) passes records with no status. State what you allow instead.

16. Secrets in browsers

A secret key bypasses every rule. The browser build refuses to start with one; don’t override that.

17. Comparing case-sensitively

"Admin" is not "admin". Store normalised values; role names are lowercase.

18. Over-clever rules

If you can’t explain a rule in a sentence, split it into named rules. Complex rules hide bugs.

Testing

Catch these.

Debugging

Diagnose them.