Alinea ships with a built-in role-based access control system. Roles are defined alongside your CMS configuration and describe exactly what each class of editor can do — down to individual fields. TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/alineacms/alinea/llms.txt
Use this file to discover all available pages before exploring further.
admin role is always present and grants full access; any additional roles you define stack on top of it for your specific use cases.
Defining a role
UseConfig.role to create a role. It takes a display label and an options object whose permissions function receives a WriteablePolicy that you populate with policy.set(...) calls.
cms.config.ts
roles object is passed directly to createCMS. Alinea automatically includes the built-in admin role — you don’t need to add it yourself.
The Permissions interface
Every permission target uses an allow and/or deny map whose keys come from the Permissions interface.
| Permission | Controls |
|---|---|
read | Whether the editor can see this resource |
create | Whether the editor can create new entries |
update | Whether the editor can edit existing entries or field values |
delete | Whether the editor can delete entries |
reorder | Whether the editor can drag entries to a new position |
move | Whether the editor can move entries between roots |
publish | Whether the editor can publish drafts |
archive | Whether the editor can archive entries |
upload | Whether the editor can upload media files |
explore | Whether the editor can browse the media library |
all | Shorthand that covers every permission above |
Partial<Permissions> shape
Targeting permissions with PermissionInput
Each call to policy.set() takes one or more PermissionInput objects. A PermissionInput specifies where the permission applies and what is allowed or denied.
Permissions can be scoped to any of the following targets:
| Key | Type | Description |
|---|---|---|
workspace | Workspace | Applies to a whole workspace |
root | Root | Applies to a specific root |
type | Type | Applies to all entries of a type |
field | Field | Applies to a single field |
id | string | Applies to one entry by its ID |
locale | string | null | Applies to entries in a specific locale |
| (none) | — | Global — applies at the root policy level |
allow and deny maps and an optional grant strategy.
The grant strategy
Controls how higher-level permissions interact with this target.
inherit(default) — a permission granted at a higher level (e.g. workspace) is sufficient for this target too.explicit— a permission must be set directly on this target; inherited permissions from a parent scope are ignored.
explicit when you want to lock down a resource and only open up individual sub-resources by hand.Using grant: 'explicit' to lock down a workspace
Field-level permissions
The most granular level of control is the individual field. Denyingupdate on a field makes it read-only in the editor UI. Denying read hides it completely.
apps/dev/src/schema/example/FieldPermissions.tsx
Field-level deny rules
Config.role options
The display name of the role as it appears in the dashboard’s user management interface.
A short description explaining what this role is for. Shown in the dashboard alongside the role name.
A function that receives a mutable
WriteablePolicy and (optionally) a Graph instance for data-driven permission rules. Call policy.set(...) with one or more PermissionInput objects, or policy.allowAll() to grant everything.Registering roles in createCMS
A map of role keys to
Role objects created with Config.role. The admin role is always included automatically. Users are assigned roles in the dashboard’s user management section.Registering multiple roles
The built-in admin role
Alinea always adds an admin role that calls policy.allowAll() internally. Admins can do everything without restriction. This role cannot be removed or overridden.