What row-level security means
Most access bugs come from checking permissions in the app, where a determined person can route around them. Row-level security moves the decision to the data itself. Each record carries the rule for who may read or write it, and the server enforces that rule on every query. The client cannot ask for more than the rule allows.
Row-level security in SQL
In Postgres and tools built on it, row-level security is a set of policies you write per table in SQL. You enable it, then define who can select, insert, update and delete which rows. It is flexible and correct when done right, but you have to get it right on every table. If RLS is off on a table, or a policy is too loose, the query returns rows it shouldn't, with no error.
Gemmein's eight safety rules
Every collection has one of eight plain-English safety rules. You choose it in the collection’s file in your project, and the server enforces it on every read and write. There is nothing to enable and no policy to leave open.
| Rule | What it means |
|---|---|
private | Each signed-in person sees and edits only their own records. |
shared | Every signed-in person reads every record and adds their own. |
admin_write | Everyone signed in can read. Only the app owner can write. |
public_read | Readable without signing in. Only the app owner writes. |
community | Readable without signing in. Any signed-in person posts and edits their own. |
addressed | The app owner creates records for one person. That person's list returns only their own, like an inbox. |
direct | People send to each other. The app owner can read them. |
app_only | Nobody using the app reads or writes it. Only the app owner, their server and relays reach it. |
// On a "private" collection, this returns only the signed-in person's records.
const { records } = await g.collection("notes").list({ limit: 20 });Map a policy to a safety rule
If you write RLS policies today, choose the safety rule that matches the policy's intent.
| The policy you would write | The Gemmein rule |
|---|---|
| A user can select and update only rows where user_id = auth.uid() | private |
| Everyone reads, without signing in; a signed-in person writes their own rows | community |
| Everyone signed in reads; a signed-in person writes their own rows | shared |
| Anyone reads; only the app owner writes | public_read |
| Everyone signed in reads; only the app owner writes | admin_write |
| Deliver one record to one specific person | addressed |
| No client role can select or write; only the service role reaches the table | app_only |
Prompt for your coding agent
Paste this into Cursor, Claude, Bolt or Lovable so your agent picks the right safety rule and writes no access checks of its own.
Read https://docs.gemmein.com/llms.txt. I want row-level security for my app's data without writing SQL policies. Explain the eight safety rules (private, shared, admin_write, public_read, community, addressed, direct, app_only) and, for each collection in my app, pick the rule that keeps each person's data correctly scoped. Show how a list query returns only what the rule allows.
npx gemmein devRead the getting-started guideFrequently asked questions
Can row-level security be turned off or misconfigured?
It cannot be turned off. Every collection has a safety rule, always on and enforced on the server, with no switch to disable it and no policy to leave open. The choice you make is the rule itself, so pick the one that matches who should read the data: personal data belongs on private, never on public_read.