Skip to content

Roles & Permissions

This is the reference for the role-based access control system — available roles, permissions, and the helper functions used to enforce them in collections and fields.

Role Access Level
ADMIN Full access to everything
EDITOR Content management per permissions
import { USER_ROLES } from '@/lib/payload/roles/roles';
USER_ROLES.ADMIN; // 'admin'
USER_ROLES.EDITOR; // 'editor'

Always import role strings from USER_ROLES rather than using literals — a typo in a string fails silently at runtime, while a bad constant fails at compile time.

Permission Allows
MANAGE_USERS Create, update, delete users
CREATE_CONTENT Create new documents
EDIT_OWN_CONTENT Edit own documents
EDIT_ALL_CONTENT Edit any document
DELETE_OWN_CONTENT Delete own documents
DELETE_ALL_CONTENT Delete any document
PUBLISH_CONTENT Publish documents
VIEW_AUDIT_LOGS View system logs
Function Use Case
isAuthenticated Any logged-in user
isAdmin Only admins
canViewDocument('field') Users see own; editors/admins see all
canEditDocument('field') Users edit own; editors/admins edit all
canDeleteDocument('field') Users delete own; editors/admins delete all

Direct check:

import { hasPermission, PERMISSIONS } from '@/lib/payload/roles/permissions';
if (hasPermission(user.role, PERMISSIONS.EDIT_ALL_CONTENT)) {
// User can edit any document
}

hasPermission looks up the role in rolePermissions and returns whether the given permission constant is in its list.

In collection access control:

import { requirePermission } from '@/lib/payload/roles/permissions';
access: {
create: isAuthenticated,
read: canViewDocument('author'),
update: requirePermission(PERMISSIONS.EDIT_ALL_CONTENT),
}

Each access key accepts a function that receives the request context and returns a boolean. requirePermission returns one of these functions, ready to be used directly.

In field access control:

{
name: 'internalNotes',
type: 'textarea',
access: {
read: isAdmin,
create: isAdmin,
update: isAdmin,
},
}

Field-level access control works the same way as collection-level — the same functions apply. Fields hidden by access control are simply absent from the API response rather than returning an error.

  • Always check req.user exists before checking permissions
  • Use helper functions instead of inline checks
  • Test with different roles to verify access

See Managing Roles for adding new roles and admin lockout recovery.