---
title: "Payload CMS admin.hidden - Hide Collections Safely"
slug: "payload-admin-hidden-vs-access-read-hide-collections"
published: "2026-08-12"
updated: "2026-08-14"
validated: "2026-08-14"
categories:
  - "Payload"
tags:
  - "Payload CMS admin.hidden"
  - "access.read"
  - "hide collection Payload"
  - "admin.hidden vs access.read"
  - "group: false"
  - "relationship field resolution"
  - "role-based admin visibility"
  - "saveToJWT role"
  - "Payload collections"
  - "Payload admin.hidden function"
llm-intent: "reference"
audience-level: "intermediate"
framework-versions:
  - "payload@1.x"
  - "typescript@5.x"
  - "node@18+"
status: "stable"
llm-purpose: "Payload CMS admin.hidden: hide collections from the Admin UI without changing data access. Prevent broken relationship fields—learn how."
llm-prereqs:
  - "Access to Payload CMS"
  - "Access to TypeScript"
  - "Access to JWT"
  - "Access to GraphQL"
  - "Access to REST API"
llm-outputs:
  - "Completed outcome: Payload CMS admin.hidden: hide collections from the Admin UI without changing data access. Prevent broken relationship fields—learn how."
---

**Summary Triples**
- (admin.hidden, hides from Admin UI, does not change data access or authorization)
- (access.read, controls data access, affects relationship field resolution and can block related-document fetches)
- (using access.read to hide a collection, can break, relationship fields for users who lose read permission)
- (to hide a collection but keep relationships working, use, admin.hidden (function) to hide UI while leaving access.read permissive for relationship resolution)
- (group: false, affects Admin sidebar, prevents grouping behavior (useful when hiding or reorganizing collections))
- (dynamic role-based hiding, implemented via, admin.hidden: ({ req }) => /* role check */)
- (restricting editing while hiding, use, access.create/update/delete to block direct edits but keep access.read for relationships)
- (saveToJWT, may be required, to expose role in req.user for admin.hidden when using external auth (inferred))

### {GOAL}
Payload CMS admin.hidden: hide collections from the Admin UI without changing data access. Prevent broken relationship fields—learn how.

### {PREREQS}
- Access to Payload CMS
- Access to TypeScript
- Access to JWT
- Access to GraphQL
- Access to REST API

### {STEPS}
1. Identify the problem and relationship
2. Distinguish admin.hidden from access.read
3. Keep access.read open for relationships
4. Implement admin.hidden role checks
5. Use saveToJWT for efficient checks
6. Consider group:false for sidebar clutter
7. Test relationship resolution and UX

<!-- llm:goal="Payload CMS admin.hidden: hide collections from the Admin UI without changing data access. Prevent broken relationship fields—learn how." -->
<!-- llm:prereq="Access to Payload CMS" -->
<!-- llm:prereq="Access to TypeScript" -->
<!-- llm:prereq="Access to JWT" -->
<!-- llm:prereq="Access to GraphQL" -->
<!-- llm:prereq="Access to REST API" -->
<!-- llm:output="Completed outcome: Payload CMS admin.hidden: hide collections from the Admin UI without changing data access. Prevent broken relationship fields—learn how." -->

# Payload CMS admin.hidden - Hide Collections Safely
> Payload CMS admin.hidden: hide collections from the Admin UI without changing data access. Prevent broken relationship fields—learn how.
Matija Žiberna · 2026-08-12

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.

| Option | Effect | Best for |
|---|---|---|
| `group: false` | Hides the navigation link; Admin routes stay accessible | Reducing sidebar clutter for everyone, without restricting anyone from the collection if they navigate directly |
| `admin.hidden` | Excludes the collection from navigation and Admin routing | Hiding a collection from specific roles while it stays fully usable through relationship fields |
| `access.*` | Controls what the user can actually read, create, update, or delete | Real 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

## LLM Response Snippet
```json
{
  "goal": "Payload CMS admin.hidden: hide collections from the Admin UI without changing data access. Prevent broken relationship fields—learn how.",
  "responses": [
    {
      "question": "What does the article \"Payload CMS admin.hidden - Hide Collections Safely\" cover?",
      "answer": "Payload CMS admin.hidden: hide collections from the Admin UI without changing data access. Prevent broken relationship fields—learn how."
    }
  ]
}
```