Permissions
Frappe's permission model is role-based, with optional record-level overrides. Get this right early — retrofitting permissions on a live site is painful.
The three layers
| Layer | Granularity | Where to set |
|---|---|---|
| Role Permissions | Per DocType per role | Role Permissions Manager |
| User Permissions | Restrict a user to records linked to specific master values | User → User Permissions |
| Share | One-off per-document grant | Document → Menu → Share |
Role Permissions
Open Role Permissions Manager, pick a DocType, and configure for each role: read, write, create, submit, cancel, delete, plus level-based field hiding. Frappe combines permissions across all of a user's roles — most permissive wins.
User Permissions
Suppose user alice@x.com should only see Sales Invoices for Customer A. You don't change the role — you add a User Permission: Customer = A. Frappe then filters Customer-linked documents server-side. Compounding permissions works (alice can have several customers).
Permission levels (column hiding)
Each field has a permlevel (default 0). Roles can be granted/denied access per level. Use this to hide sensitive fields (cost prices, salary) from some roles while still showing the document.
Sharing
For a one-off — "let Bob see this one Sales Invoice" — use Share from the document menu. Lighter than creating a role; not for systemic use.
Permission Query Conditions (developer)
For dynamic rules ("see only documents you created" or "see only documents in your region"), apps can register a permission_query_conditions hook returning a SQL fragment. Server-side filtering, not just UI hiding.