Roles and Permissions in Netlify CMS / Decap CMS | OpsBlu Docs

Roles and Permissions in Netlify CMS / Decap CMS

Configure user roles, permissions, and access control for Netlify CMS and Decap CMS

Netlify CMS (now Decap CMS) doesn't have built-in role management like WordPress or traditional CMSs. Instead, it relies on Git provider permissions and editorial workflow configuration. This guide explains how to implement role-based access control.

Understanding Netlify CMS Permission Model

Git-Based Permissions

Netlify CMS inherits permissions from your Git provider:

Repository Permission = CMS Permission

Git Provider Permission Level CMS Access Can Edit Can Publish
GitHub Read View only No No
GitHub Write Full access Yes Via PR
GitHub Admin Full access Yes Yes (direct merge)
GitLab Guest No access No No
GitLab Reporter View only No No
GitLab Developer Full access Yes Via MR
GitLab Maintainer Full access Yes Yes (direct merge)
Bitbucket Read View only No No
Bitbucket Write Full access Yes Via PR
Bitbucket Admin Full access Yes Yes (direct merge)

No Database-Level Roles

Unlike WordPress (Admin, Editor, Author, Contributor), Netlify CMS has no user database:

WordPress Approach:

Admin > Editor > Author > Contributor > Subscriber

Netlify CMS Approach:

Repository permissions + Editorial workflow + Branch protection

Implementing Role-Based Access

Editorial Workflow for Access Control

Enable editorial workflow to create a review process:

# static/admin/config.yml
backend:
  name: github  # or gitlab, bitbucket
  repo: your-username/your-repo
  branch: main

publish_mode: editorial_workflow

# Optional settings
media_folder: "static/uploads"
public_folder: "/uploads"

collections:
  - name: "blog"
    label: "Blog"
    folder: "content/blog"
    create: true
    fields:
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Body", name: "body", widget: "markdown"}

Workflow Stages

1. Draft

  • Who: Anyone with Write/Developer permission
  • What: Create content, save drafts
  • Git: No commit yet (stored in browser localStorage or as branch)

2. In Review

  • Who: Content creators move to review
  • What: Creates pull/merge request
  • Git: Creates feature branch, opens PR/MR

3. Ready

  • Who: Reviewers (users with merge permission)
  • What: Approve content for publishing
  • Git: Approval recorded on PR/MR

4. Published

  • Who: Users with merge permission
  • What: Merge to main branch
  • Git: PR/MR merged, triggers build

Role Patterns

Pattern 1: Content Creator Role

Goal: Users can create/edit but not publish directly.

Implementation:

1. GitHub Configuration:

Repository → Settings → Branches → Branch protection rules

Branch: main
☑ Require pull request reviews before merging
  Required approvals: 1
☑ Restrict who can push to matching branches
  (Don't include content creators)

2. Grant Write Access:

Repository → Settings → Collaborators → Add people
Permissions: Write

3. Editorial Workflow:

# config.yml
publish_mode: editorial_workflow

Result:

  • Content creators can edit via CMS
  • Changes create PRs automatically
  • Cannot merge (publish) directly
  • Requires reviewer approval

Pattern 2: Reviewer Role

Goal: Users can review and approve content.

Implementation:

1. GitHub Configuration:

Settings → Branches → Branch protection

☑ Require pull request reviews before merging
  Required approvals: 1

Reviewers:
- Add specific users or teams

2. Grant Write or Admin Access:

Collaborators → Add reviewer
Permissions: Write (can approve) or Admin (can approve and merge)

3. Review Process:

  1. Content creator submits to "In Review"
  2. PR created automatically
  3. Reviewer sees notification
  4. Reviewer approves via GitHub/CMS
  5. Reviewer or admin merges to publish

Pattern 3: Publisher Role

Goal: Users can publish content directly without review.

Implementation:

1. Grant Admin Permission:

Repository → Collaborators → Add people
Permissions: Admin

2. No Branch Protection (or exempt admins):

Settings → Branches → Branch protection

☑ Include administrators
  (Unchecked - admins can bypass protection)

3. Direct Publish:

# config.yml
# No editorial_workflow - direct commits to main
publish_mode: simple  # or omit, defaults to simple

Result:

  • Publishers can commit directly to main
  • No PR required
  • Immediate publication

Pattern 4: Read-Only Role

Goal: Users can view content in CMS but not edit.

Implementation:

1. GitHub Read Permission:

Collaborators → Add people
Permissions: Read

2. CMS Behavior:

  • User can log in to CMS
  • Can browse content
  • Cannot edit, save, or publish
  • "Edit" button disabled

Note: This is limited functionality. Most read-only users don't need CMS access.

Collection-Level Permissions

Restrict Collections by User

While Netlify CMS doesn't have built-in user-based collection filtering, you can implement it:

Option 1: Separate Repositories

blog-repo → Blog editors access this
docs-repo → Documentation team access this

Option 2: Git Branches

# config.yml for blog editors
backend:
  name: github
  repo: your-org/content
  branch: blog  # Only edit blog branch

# config.yml for docs team
backend:
  name: github
  repo: your-org/content
  branch: docs  # Only edit docs branch

Option 3: Custom CMS Builds

Build separate CMS instances with different config.yml:

/admin/blog/config.yml    → Blog collections only
/admin/docs/config.yml    → Docs collections only

Deploy at different URLs:

  • yoursite.com/admin/blog → Blog team
  • yoursite.com/admin/docs → Docs team

Advanced Permission Patterns

GitHub Teams

Manage groups of users:

1. Create Team:

Organization → Teams → New team
Team name: "Content Editors"

2. Add Team to Repository:

Repository → Settings → Collaborators and teams
Add team: "Content Editors"
Permissions: Write

3. Branch Protection with Teams:

Settings → Branches → Branch protection

Required approvals: 1
Restrict who can dismiss reviews:
  Teams: "Senior Editors"

Benefits:

  • Manage multiple users at once
  • Consistent permissions across repos
  • Easy onboarding/offboarding

GitLab Groups

Similar to GitHub teams:

1. Create Group:

GitLab → Groups → New group

2. Add Members to Group:

Group → Members → Invite
Role: Developer, Maintainer, etc.

3. Add Group to Project:

Project → Members → Invite group
Role: Developer

CODEOWNERS File

Define who must review specific files:

# .github/CODEOWNERS

# Blog posts require blog-team approval
/content/blog/**       @your-org/blog-team

# Documentation requires docs-team approval
/content/docs/**       @your-org/docs-team

# Site config requires admin approval
/static/admin/**       @your-org/admins

Enforcement:

Settings → Branches → Branch protection

☑ Require review from Code Owners

Custom Authentication

Implementing Custom Roles

For advanced role management beyond Git permissions:

Option 1: Netlify Identity with Metadata

# config.yml
backend:
  name: git-gateway

Add user metadata via Netlify API:

// Add role metadata to user
const response = await fetch(`https://api.netlify.com/api/v1/sites/${siteId}/identity/users/${userId}`, {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    app_metadata: {
      role: 'editor'  // or 'admin', 'reviewer'
    }
  })
});

Read role in CMS:

// custom-cms-widget.js
const user = netlifyIdentity.currentUser();
const role = user.app_metadata.role;

if (role === 'editor') {
  // Show only specific collections
}

Option 2: Custom Backend

Build custom authentication backend:

# config.yml
backend:
  name: custom
  url: https://your-api.com/netlify-cms-auth

Implement custom backend that:

  1. Authenticates users
  2. Returns user roles
  3. Filters collections based on role
  4. Controls publish permissions

Permission Troubleshooting

User Can't Edit

Symptom: User logs in but sees read-only interface.

Checklist:

  • User has Write/Developer permission (not Read/Reporter)
  • Repository permissions synced (may take a few minutes)
  • User authenticated with correct account
  • CMS config points to correct repository

Fix:

  1. Verify user's Git provider permission
  2. Increase to Write/Developer
  3. User logs out and logs back in to CMS

User Can Edit But Can't Publish

Symptom: User can save drafts but publish fails.

Causes:

  • Branch protection enabled
  • User lacks merge permission
  • Editorial workflow misconfigured

Fix:

If editorial workflow enabled:

  • Expected behavior - user should submit for review
  • Reviewer with merge permission must approve

If direct publish desired:

  • Grant user Admin permission
  • Or exempt from branch protection

Changes Not Appearing

Symptom: User publishes but changes don't appear on site.

Checklist:

  • PR/MR actually merged
  • Build triggered after merge
  • Build succeeded (check Netlify deploy log)
  • Cache cleared

Fix:

  1. Check Netlify → Deploys
  2. Verify merge happened in Git provider
  3. Trigger manual deploy if needed

Best Practices

1. Start with Editorial Workflow

Always recommend:

publish_mode: editorial_workflow

Benefits:

  • Preview changes before publish
  • Peer review process
  • Git history of approvals
  • Easy rollback

2. Protect Main Branch

Minimum protection:

☑ Require pull request reviews
☑ Require status checks to pass

3. Use Teams/Groups

Instead of:

Individual users: alice, bob, carol, david...

Use:

Teams: content-editors, reviewers, admins

4. Audit Regularly

Monthly review:

  • Active users
  • Permission levels
  • Unused accounts
  • Team memberships

5. Document Your Workflow

Create internal documentation:

# Content Publishing Workflow

## Roles

**Content Creators** (Write permission)
- Create drafts
- Edit content
- Submit for review

**Reviewers** (Write permission + Code Owner)
- Review submissions
- Request changes
- Approve content

**Publishers** (Admin permission)
- Merge approved content
- Emergency hotfixes
- Configuration changes

Next Steps