---
title: "Collection Config"
aliases: [collections, payload-collections, collection-configuration]
tags: [payloadcms, collections, config, schema, admin]
sources: [raw/configuration__collections.md]
created: 2026-05-15
updated: 2026-05-15
---

## Overview

A Collection is a group of Documents sharing a common schema. Each Collection auto-generates [[wiki/payloadcms/local-api|Local API]], [[wiki/payloadcms/rest-api|REST API]], and GraphQL API.

```ts
import { buildConfig } from 'payload'

export default buildConfig({
  collections: [Posts, Users],
})
```

> If a Collection should hold only one Document, use a Global instead.

## Required Properties

| Property | Description |
|----------|-------------|
| `slug`   | Unique URL-friendly identifier (e.g. `'posts'`) |
| `fields` | Array of field definitions — see [[wiki/payloadcms/queries|Queries]] for field types |

## Key Config Options

| Option | Description |
|--------|-------------|
| `access` | Per-operation access control functions |
| `auth` | Enable authentication on this Collection |
| `hooks` | Lifecycle hooks (beforeChange, afterRead, etc.) |
| `versions` | Enable drafts/versioning (`true` or config object) |
| `upload` | Enable file uploads |
| `timestamps` | Set `false` to disable `createdAt`/`updatedAt` |
| `trash` | `true` for soft-deletes |
| `orderable` | Enable drag-and-drop ordering (fractional indexing) |
| `indexes` | Compound DB indexes for performance/uniqueness |
| `defaultSort` | Default sort field; prefix `-` for descending |
| `disableDuplicate` | Hide "Duplicate" button and API action |
| `disableBulkEdit` | Disable bulk edit in admin + REST API |
| `lockDocuments` | Document locking config (enabled by default) |
| `dbName` | Override DB table/collection name |
| `defaultPopulate` | Fields to select when populated from other documents |
| `select` | Function to force fields populated for hooks/access control |
| `hierarchy` | Enable parent-child tree structure |
| `enableQueryPresets` | Enable saved query presets for this Collection |
| `endpoints` | Add custom REST routes; `false` to disable all |

## Admin Options (`admin.*`)

| Option | Description |
|--------|-------------|
| `useAsTitle` | Top-level field used as document title in admin |
| `defaultColumns` | Fields shown as columns in List View by default |
| `listSearchableFields` | Fields searched by the List View search box |
| `pagination` | `{ defaultLimit, limits }` — List View pagination |
| `group` | Nav group label; `false` to hide from nav |
| `hidden` | `true` or function — exclude from nav/routing |
| `preview` | Function returning preview URL |
| `livePreview` | Real-time preview config |
| `baseFilter` | Default filter applied to List View |
| `folders` | Enable folder grouping (beta) |
| `formatDocURL` | Customize/disable document links in List View |
| `components` | Inject custom React components |

### `useAsTitle` Gotcha

If set to a relationship/join field, only the related doc's ID is used as title. To show a specific field from the related doc, create a virtual field and point `useAsTitle` to that.

### List Searchable Fields

Index each `listSearchableFields` entry to keep admin queries fast:

```ts
admin: {
  listSearchableFields: ['title', 'slug'],
}
```

## Orderable — Fractional Indexing

When `orderable: true`, drag-and-drop reordering is enabled using fractional indexing. Generate keys programmatically:

```ts
import { generateKeyBetween, generateNKeysBetween } from 'payload/shared'

const newKey = generateKeyBetween('a0', 'a1')       // between two keys
const startKey = generateKeyBetween(null, 'a0')     // before first
const endKey = generateKeyBetween('a1', null)       // after last
const keys = generateNKeysBetween('a0', 'a1', 5)   // 5 keys between
```

## Custom Components (`admin.components.*`)

### List View Components

| Slot | Description |
|------|-------------|
| `beforeList` / `afterList` | Inject components before/after the table |
| `beforeListTable` / `afterListTable` | Inject within table area |
| `listMenuItems` | Menu items next to Columns/Filters |
| `Description` | Custom description below collection label |

### Edit View Components (`admin.components.edit.*`)

| Slot | Requirement |
|------|-------------|
| `SaveButton` | Drafts must be disabled |
| `SaveDraftButton` | Drafts enabled, autosave disabled |
| `PublishButton` / `UnpublishButton` | Drafts must be enabled |
| `Status` | Drafts must be enabled |
| `PreviewButton` | Preview must be enabled |
| `Upload` | Upload must be enabled |
| `beforeDocumentControls` | Always available |
| `editMenuItems` | Always available (3-dot menu) |

> Components under `edit.*` must go in `admin.components.edit`, not `admin.components`.

## List View Select API

The List View fetches only active column fields (not full documents). Hooks relying on unselected fields will receive `undefined`. Force a field to always be present:

```ts
export const Posts: CollectionConfig = {
  select: ({ select }) => ({ ...select, title: true }),
}
```

## Format Document URLs

Customize or disable links in the List View:

```ts
admin: {
  formatDocURL: ({ doc, defaultURL, req, collectionSlug, viewType }) => {
    if (doc.status === 'private') return null      // disable link
    if (req.user?.role === 'admin') return defaultURL + '?admin=true'
    return defaultURL
  },
}
```

Returns `null` (no link), a custom string URL, or `defaultURL`.

## GraphQL Options

```ts
graphQL: false  // disable entirely
// or:
graphQL: {
  singularName: 'Post',
  pluralName: 'Posts',
  disableQueries: false,
  disableMutations: false,
}
```

## TypeScript

```ts
import type { CollectionConfig, SanitizedCollectionConfig } from 'payload'
```

Use `CollectionConfig` when authoring. `SanitizedCollectionConfig` is the post-sanitization form used internally.

## Key Takeaways

- `slug` and `fields` are the only required properties
- Each Collection auto-generates Local, REST, and GraphQL APIs
- `auth: {}` turns a Collection into a user/auth entity
- `orderable` uses fractional indexing — import `generateKeyBetween` from `payload/shared` for programmatic ordering
- List View uses Select API — hooks on inactive columns will get `undefined`; use top-level `select` config to force fields
- Edit view custom components must be nested under `admin.components.edit`, not `admin.components`
- `useAsTitle` on a relationship field shows only the ID — use a virtual field to expose specific related data
- Index `listSearchableFields` in your DB for performance

## Sources

- `raw/configuration__collections.md`
- Official docs: https://payloadcms.com/docs/configuration/collections
