BuildWithMatija
  1. Home
  2. Blog
  3. Payload
  4. Payload CMS admin.hidden - Hide Collections Safely

Payload CMS admin.hidden - Hide Collections Safely

Understand admin.hidden vs access.read in Payload CMS to hide collections from the UI without breaking relationship…

12th August 2026·Updated on:14th August 2026··
Payload
Payload CMS admin.hidden - Hide Collections Safely

Evaluating Payload CMS Implementation Costs?

Scope design, content structure, and migration hours to estimate a realistic production timeline and hosting setup.

Try the Cost EstimatorGet a Second Opinion

📚 Comprehensive Payload CMS Guides

Detailed Payload guides with field configuration examples, custom components, and workflow optimization tips to speed up your CMS development process.

No spam. Unsubscribe anytime.

📄View markdown version
0

Frequently Asked Questions

About the author

Matija Žiberna

Matija Žiberna

Full-stack developer, co-founder

AboutResume

Self-taught full-stack developer sharing lessons from building software and startups.

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.

Contents

  • The problem: hiding a collection without hiding its data
  • The mental model
  • Implementation: `admin.hidden` with a role check
  • Role-based visibility
  • `group: false` is a different tool
  • FAQ
  • Conclusion
On this page:
  • The problem: hiding a collection without hiding its data
  • The mental model
  • Implementation: `admin.hidden` with a role check
  • Role-based visibility
  • `group: false` is a different tool
Build with Matija logo

Build with Matija

Senior-led B2B websites, applications, content systems, and digital infrastructure. Business-first, full-stack, AI-assisted, no handoffs.

Services

  • B2B Website Development
  • CMS Architecture Review & Platform Blueprint
  • Next.js + Payload Advisory
  • AI Integration & Implementation

Resources

  • CMS Hub
  • B2B Website Strategy
  • E-commerce Hub
  • Blog
  • Case Studies

Payload CMS

  • Payload CMS Developer
  • Payload CMS Migration
  • Payload CMS Demos
  • All Payload CMS Resources

Discuss your project

Planning a rebuild, migration, application, workflow change, or platform decision? Start with the business problem and the system behind it.

Book a discovery callContact me →
© 2026Build with Matija•All rights reserved•Privacy Policy•Terms of Service
BuildWithMatija
Get In Touch

Payload CMS separates two decisions that look similar on the surface: whether a collection shows up in the Admin Panel, and whether a user can actually read its data. admin.hidden controls the first. access.read controls the second. Collapsing them into a single access check is what breaks a relationship field somewhere else in your CMS. This guide walks through the distinction using a real collection structure, then covers dynamic role-based hiding and the related group: false option.

I recently ran into this while working on a Payload project with a Component field on Pages that pulls its options from a Component Configurations collection. Editors needed to pick a configuration while editing a Page. They had no reason to open Component Configurations directly and manage it as its own thing.

The problem: hiding a collection without hiding its data

Here's the relationship structure:

text
Pages
  └── Component
       └── Configuration → Component Configurations

An editor selects a curated configuration while editing a Page. That configuration lives in its own collection, Component Configurations, which does not need a place in the Admin sidebar for that editor.

My first instinct was to reach for access control to keep that collection out of view:

ts
access: {
  read: ({ req }) => req.user?.role === 'admin'
}

This restricts read access to admins only. It also removes an editor's ability to read Component Configurations documents at all, including through the relationship field on Pages. The configuration picker breaks, because Payload can no longer resolve the related documents for that editor's request.

Removing read access changes real authorization. The sidebar disappearing is a side effect. The relationship field breaking is the actual cost.

The mental model

Payload treats these as two separate questions:

text
admin.hidden
↓
Should this collection appear in the Payload Admin UI?

access.read
↓
Is this user actually allowed to read this data?

Collection access control governs what a user can do with documents through the API and through relationship resolution. admin.hidden governs what shows up in the Admin Panel. Keeping those two concerns apart is what makes the pattern work.

Implementation: admin.hidden with a role check

Here's the same collection with the distinction applied correctly:

ts
// File: collections/ComponentConfigurations.ts
import type { CollectionConfig } from 'payload'

export const ComponentConfigurations: CollectionConfig = {
  slug: 'component-configurations',

  access: {
    read: () => true,
  },

  admin: {
    hidden: ({ user }) => {
      return user?.role !== 'admin'
    },
  },

  fields: [
    // ...
  ],
}

access.read stays open, so any authenticated request, including the relationship field resolving inside a Page, can read Component Configurations documents. admin.hidden runs a function that receives the current user and returns true for anyone who is not an admin, which excludes the collection from Admin navigation and Admin routing for everyone else. Payload's documentation defines admin.hidden as either a boolean or a function taking the current user, with a true result excluding the collection from the Admin UI entirely.

An editor can now select a configuration on a Page exactly as before. The Component Configurations collection itself never appears as something they navigate to and manage on its own.

A useful rule to keep this straight going forward:

text
Security requirement → access.*
Admin UX requirement → admin.*

If the requirement is "this role cannot read this data," it belongs in access. If the requirement is "this collection should not clutter this role's Admin Panel," it belongs in admin.

Role-based visibility

admin.hidden can run any logic based on the authenticated user, not just a single role check:

ts
// File: collections/ComponentConfigurations.ts
admin: {
  hidden: ({ user }) => {
    return !user?.roles?.includes('admin')
  },
}

For this to work, the fields you're checking need to be present on the authenticated user object, which means they need to be available on the JWT. Payload includes a field on the token when saveToJWT is set:

ts
// File: collections/Users.ts
{
  name: 'role',
  type: 'select',
  options: ['admin', 'editor'],
  saveToJWT: true,
}

With role saved to the JWT, the hidden function has access to it on every request without an extra database lookup. This keeps role-based Admin visibility a UI concern, separate from the authorization logic in access.

group: false is a different tool

Payload also offers group: false, which looks similar to admin.hidden but solves a different problem:

ts
// File: collections/ComponentConfigurations.ts
admin: {
  group: false,
}

group: false removes the collection's link from Admin navigation for everyone, while its Admin routes stay reachable. Someone with a direct URL to the collection's list or document view can still open it. admin.hidden removes the collection from both navigation and Admin routing, so the collection becomes unreachable through the Admin Panel entirely for whoever the hidden function returns true for.

OptionEffectBest for
group: falseHides the navigation link; Admin routes stay accessibleReducing sidebar clutter for everyone, without restricting anyone from the collection if they navigate directly
admin.hiddenExcludes the collection from navigation and Admin routingHiding a collection from specific roles while it stays fully usable through relationship fields
access.*Controls what the user can actually read, create, update, or deleteReal authorization decisions about the data itself

A collection can stay hidden from an editor in the Admin Panel and remain fully usable to that same editor through a relationship field elsewhere in the CMS. Keeping admin.* and access.* as separate decisions is what makes that possible, and it's what keeps a UI cleanup task from quietly turning into an authorization change.

FAQ

Does admin.hidden affect the Payload REST or GraphQL API? No. admin.hidden only affects the Admin Panel. API access is controlled entirely by access.*, so a hidden collection remains fully queryable by anyone who passes its access control checks.

Can I use admin.hidden on fields as well as collections? Yes. Payload supports admin.hidden at the field level too, using the same boolean-or-function pattern, which lets you hide specific fields from the Admin UI without touching their access control.

What happens to a relationship field if the related collection is fully inaccessible through access.read? The relationship will fail to resolve for that user, since reading the related documents requires passing access.read. This is the exact failure mode admin.hidden avoids, because it never touches access.read.

Should group: false and admin.hidden ever be used together? Rarely, since admin.hidden already removes the collection from navigation. group: false is more useful on its own when you want a collection off the sidebar for every user while keeping its Admin routes directly reachable.

Does the hidden function run on every request? It runs whenever Payload builds the Admin navigation and resolves Admin routing for the current user, so it reflects the authenticated user's current state on each request rather than being cached per session.

Conclusion

Hiding a collection from the Admin Panel and restricting who can read its data are two separate requirements in Payload CMS. access.read decides real authorization. admin.hidden decides what shows up in the Admin UI, and it can run per-user logic using fields saved to the JWT. group: false handles a narrower case: hiding the navigation link for everyone while leaving Admin routes reachable. Using the right tool for each requirement keeps a UI cleanup from turning into a broken relationship field somewhere else in your schema.

Let me know in the comments if you have questions, and subscribe for more practical development guides.

Thanks, Matija