A rule decides from the facts it’s given: who is calling ($auth), the record ($record), what’s being sent ($input), the request, the key and the environment. That covers most needs, and it’s what lets a rule run inside the database query for lists. It can’t: This page shows how to handle each, without leaving the builder.

Pattern 1: put the fact on the record

The most effective approach is usually to store what the rule needs on the record itself, and keep it up to date with a flow. Project members. Give tasks a member_ids list (a JSON array of user ids) copied from the project. A flow subscribed to project_members.created and .deleted updates the tasks of that project. The rule becomes:
  • Compare values: $record.member_ids contains $auth.user_id
It stays visible in Studio, works everywhere a rule is accepted, and needs no lookup at request time. Trade-off: a contains check on a list can’t become a database filter, so lists of that table are checked row by row and total comes back empty. For large tables, prefer pattern 3 or a dedicated join table read by your app.

Pattern 2: put the fact in the token

Facts about the person can travel in their access token, where every rule can read them under $auth.claims: Then: Compare values $auth.claims.plan is one of pro, business. When the fact changes (an upgrade), update the attribute; the next token carries it. Tokens are short-lived, so changes reach rules within minutes, or straight away when the person’s session refreshes.

Pattern 3: organizations for group membership

If “members of X” means “people in the same company”, use organizations. Records carry an org column and the rule compares it with $auth.org, which is a database filter, so lists stay exact. See Teams and organizations.

Pattern 4: let the database enforce counts and uniqueness

“One open cart per customer” or “one vote per person per post” is a unique index, not a rule: A second attempt fails with 409 unique_violation, whoever sends it. See Indexes.

Pattern 5: a flow that checks, then writes

When a write needs a real lookup or another system’s answer, make it a route or flow your app calls, and switch off the direct operation on the table:
  1. The table’s Add records is off (or Secret keys & Studio only).
  2. A route POST /tickets runs a flow that:
    • Require sign-in;
    • SQL query counts the caller’s open tickets; an If fails with 422 when there are 3 or more;
    • or HTTP request asks your billing provider whether the subscription is active;
    • Create record with the values it trusts.
The flow runs with its own authority, so it can read what the rules language can’t, and it decides exactly what’s written. See Rules on routes and flows.

Choosing

Named rules

Save and reuse rules.

Common mistakes

What to avoid.