Choosing Between Document-Level and Collection-Level Permissions in Appwrite for Multi‑Tenant Apps
Learn how to decide between Appwrite’s collection‑level and document‑level permissions, see a layered configuration example, and verify the outcome with simple SDK calls.
08 Aug 2026, 23:55 UTC

Decision: How to control who can read and write data in a multi‑tenant Appwrite database
When building a SaaS or multi‑tenant application you often need a baseline rule (e.g., "any authenticated user can read public data") combined with per‑record restrictions (e.g., "only the document owner can update their own record"). Appwrite lets you set permissions at two layers: the collection (global) and the individual document. The decision is which layer to use for each rule, or whether to combine them.
Constraints and requirements
- Public read access for non‑sensitive data.
- Write access limited to the tenant that owns the record.
- Administrators must be able to override tenant restrictions.
- Minimize ongoing permission‑management overhead as the number of documents grows.
Comparison of supported options
| Option | Where permission is set | Typical use case | Management overhead | Ability to revoke via other layer |
|---|---|---|---|---|
| Collection‑level only | Collection settings | Data that shares the same rule for every document (e.g., public blog posts). | Low – one rule per collection. | Not applicable – document‑level cannot override. |
| Document‑level only | Individual document | Strict owner‑only data (e.g., user profile). | High – a rule per document; grows with record count. | No – collection rule is ignored if absent. |
| Combined (layered) | Both collection and document | Baseline access for all authenticated users, with tighter owner‑only overrides. | Medium – collection rule set once, document rule per owner. | Collection grants are additive; document rules cannot remove collection access. |
Trade‑offs
- Simplicity vs. granularity: Collection‑level is simplest but cannot express per‑user limits. Document‑level gives fine‑grained control but creates many permission objects.
- Revocation: Because permissions are additive, a document‑level rule cannot take away access granted at the collection level. If you need to deny a user that already has collection access, you must tighten the collection rule instead.
- Performance: Permission checks are fast at both layers, but storing many document‑level ACLs increases storage and API request size.
Concrete implementation: layered approach for tenant‑specific documents
The following example shows how to configure a collection so that any authenticated user can read, but only the document’s owner can update or delete it. An administrator role (e.g., role:team:admins) retains full access.
- Create the collection (via Console or SDK) and set collection‑level permissions:
// Example using Appwrite Node SDK (replace placeholders)
const sdk = new Appwrite();
sdk.setEndpoint('https://cloud.appwrite.io/v1');
sdk.setProject('');
// Assume you have a JWT with permission to create collections
await sdk.databases.createCollection('', UNIQUE_ID(), 'tenants', [
// Collection‑level: read for any authenticated user
sdk.permission.read(Role.users()),
// Collection‑level: write for admins only (adjust as needed)
sdk.permission.write(Role.team('')),
]);
- Create a document with owner‑specific permission:
// Assuming you have the user ID of the owner
const ownerId = '';
const docData = { name: 'Acme Corp', settings: { theme: 'dark' } };
await sdk.databases.createDocument('', '', UNIQUE_ID(), docData, [
// Document‑level: owner can read, update, delete
sdk.permission.read(Role.owner(ownerId)),
sdk.permission.update(Role.owner(ownerId)),
sdk.permission.delete(Role.owner(ownerId)),
// Admins still retain write via collection rule
]);
This results in:
- Any logged‑in user can
GETthe document (collection read rule). - Only
ownerIdor a member of the admin team canPATCHorDELETE(document‑level update/delete plus collection admin write). - Regular users attempting to update receive a 403 Forbidden.
- Read test: Using an SDK session for a random authenticated user, call
getDocument. Expect a successful response with the document data. - Write test: Repeat the call with the same user but using
updateDocumentwith a payload change. Expect a 403 response unless the user matchesownerIdor belongs to the admin team. - Admin test: Perform the update using a session for a user in the admin team; expect success.
- Management overhead: As the number of tenants grows, you will create a document‑level ACL for each record. Periodically audit that no stray
role:allrules exist at the collection level, as they would unintentionally grant broad access. - Additive nature: Remember that you cannot use a document‑level rule to revoke a collection‑level grant. If you need to restrict a subset of users, tighten the collection rule or move those documents to a separate collection with a more restrictive baseline.
- Practical check: After any permission change, attempt a read/write with a user that should be denied; a 403 confirms the rule is working as intended.
Verification steps (do not claim they were run)
You can also inspect the effective permissions in the Appwrite Console under the document’s “Permissions” tab to confirm the listed roles.
Limitations and practical checks
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.