## 1. Project Overview & Quickstart (payloadcms/payload)

## File: README.md

[](https://payloadcms.com)




  [](https://github.com/payloadcms/payload/actions)
  &nbsp;
  [](https://discord.gg/payload)
  &nbsp;
  [](https://www.npmjs.com/package/payload)
  &nbsp;
  [](https://github.com/payloadcms/payload/graphs/contributors)
  &nbsp;
  [](https://www.npmjs.com/package/payload)
  &nbsp;
  [](https://twitter.com/payloadcms)

<hr/>
<h4>
<a target="_blank" href="https://payloadcms.com/docs/getting-started/what-is-payload" rel="dofollow">**Explore the Docs**</a>&nbsp;·&nbsp;<a target="_blank" href="https://payloadcms.com/community-help" rel="dofollow">**Community Help**</a>&nbsp;·&nbsp;<a target="_blank" href="https://github.com/payloadcms/payload/discussions/1539" rel="dofollow">**Roadmap**</a>&nbsp;·&nbsp;<a target="_blank" href="https://www.g2.com/products/payload-cms/reviews#reviews" rel="dofollow">**View G2 Reviews**</a>
</h4>
<hr/>

> [!IMPORTANT]
> Star this repo or keep an eye on it to follow along.

Payload is the first-ever Next.js native CMS that can install directly in your existing `/app` folder. It's the start of a new era for headless CMS.

<h3>Benefits over a regular CMS</h3>

   <li>It's both an app framework & headless CMS</li>
  <li>Deploy anywhere, including serverless on Vercel for free</li>
  <li>Combine your front+backend in the same `/app` folder if you want</li>
  <li>Don't sign up for yet another SaaS - Payload is open source</li>
  <li>Query your database in React Server Components</li>
  <li>Both admin and backend are 100% extensible</li>
  <li>No vendor lock-in</li>
  <li>Never touch ancient WP code again</li>
  <li>Build faster, never hit a roadblock</li>


## Quickstart

Before beginning to work with Payload, make sure you have all of the [required software](https://payloadcms.com/docs/getting-started/installation).

```text
pnpx create-payload-app@latest
```

**If you're new to Payload, you should start with the website template** (`pnpx create-payload-app@latest -t website`). It shows how to do _everything_ - including custom Rich Text blocks, on-demand revalidation, live preview, and more. It comes with a frontend built with Tailwind all in one `/app` folder.

## One-click deployment options

You can deploy Payload serverlessly in one-click via Vercel and Cloudflare—giving everything you need without the hassle of the plumbing.

### Deploy on Cloudflare

Fully self-contained — one click to deploy Payload with **Workers**, **R2** for uploads, and **D1** for a globally replicated database.

[](https://dub.sh/payload-cloudflare)

### Deploy on Vercel

All-in-one on Vercel — one click to deploy Payload with a **Next.js** front end, **Neon** database, and **Vercel Blob** for media storage.

[](https://dub.sh/payload-vercel)

## One-click templates

Jumpstart your next project with a ready-to-go template. These are **production-ready, end-to-end solutions** designed to get you to market fast. Build any kind of **website**, **ecommerce store**, **blog**, or **portfolio** — complete with a modern front end built using **React Server Components** and **Tailwind**.

#### 🌐 [Website](https://github.com/payloadcms/payload/tree/main/templates/website)

#### 🛍️ [Ecommerce](https://github.com/payloadcms/payload/tree/main/templates/ecommerce) 🎉 _**NEW**_ 🎉

We're constantly adding more templates to our [**Templates Directory**](https://github.com/payloadcms/payload/tree/main/templates).
If you maintain your own, add the `payload-template` topic to your GitHub repo so others can discover it.

**🔗 Explore more:**

- [Official Templates](https://github.com/payloadcms/payload/tree/main/templates)
- [Community Templates](https://github.com/topics/payload-template)

## ✨ Payload Features

- Completely free and open-source
- Next.js native, built to run inside _your_ `/app` folder
- Use server components to extend Payload UI
- Query your database directly in server components, no need for REST / GraphQL
- Fully TypeScript with automatic types for your data
- [Auth out of the box](https://payloadcms.com/docs/authentication/overview)
- [Versions and drafts](https://payloadcms.com/docs/versions/overview)
- [Localization](https://payloadcms.com/docs/configuration/localization)
- [Block-based layout builder](https://payloadcms.com/docs/fields/blocks)
- [Customizable React admin](https://payloadcms.com/docs/admin/overview)
- [Lexical rich text editor](https://payloadcms.com/docs/fields/rich-text)
- [Conditional field logic](https://payloadcms.com/docs/fields/overview#conditional-logic)
- Extremely granular [Access Control](https://payloadcms.com/docs/access-control/overview)
- [Document and field-level hooks](https://payloadcms.com/docs/hooks/overview) for every action Payload provides
- Intensely fast API
- Highly secure thanks to HTTP-only cookies, CSRF protection, and more

<a target="_blank" href="https://github.com/payloadcms/payload/discussions">**Request Feature**</a>

## 🗒️ Documentation

Check out the [Payload website](https://payloadcms.com/docs/getting-started/what-is-payload) to find in-depth documentation for everything that Payload offers.

Migrating from v2 to v3? Check out the [3.0 Migration Guide](https://github.com/payloadcms/payload/blob/main/docs/migration-guide/overview.mdx) on how to do it.

## 🙋 Contributing

If you want to add contributions to this repository, please follow the instructions in [contributing.md](./CONTRIBUTING.md).

## 📚 Examples

The [Examples Directory](./examples) is a great resource for learning how to setup Payload in a variety of different ways, but you can also find great examples in our blog and throughout our social media.

If you'd like to run the examples, you can use `create-payload-app` to create a project from one:

```sh
npx create-payload-app --example example_name
```

You can see more examples at:

- [Examples Directory](./examples)
- [Payload Blog](https://payloadcms.com/blog)
- [Payload YouTube](https://www.youtube.com/@payloadcms)

## 🔌 Plugins

Payload is highly extensible and allows you to install or distribute plugins that add or remove functionality. There are both officially-supported and community-supported plugins available. If you maintain your own plugin, consider adding the `payload-plugin` topic to your GitHub repository for others to find.

- [Official Plugins](https://github.com/orgs/payloadcms/repositories?q=topic%3Apayload-plugin)
- [Community Plugins](https://github.com/topics/payload-plugin)

## 🚨 Need help?

There are lots of good conversations and resources in our Github Discussions board and our Discord Server. If you're struggling with something, chances are, someone's already solved what you're up against. :point_down:

- [GitHub Discussions](https://github.com/payloadcms/payload/discussions)
- [GitHub Issues](https://github.com/payloadcms/payload/issues)
- [Discord](https://t.co/30APlsQUPB)
- [Community Help](https://payloadcms.com/community-help)

## ⭐ Like what we're doing? Give us a star

## 👏 Thanks to all our contributors

---

## File: docs/access-control/collections.mdx

---
title: Collection Access Control
label: Collections
order: 20
desc: With Collection-level Access Control you can define which users can create, read, update or delete Collections.
keywords: collections, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---

Collection Access Control is [Access Control](../access-control/overview) used to restrict access to Documents within a [Collection](../getting-started/concepts#collections), as well as what they can and cannot see within the [Admin Panel](../admin/overview) as it relates to that Collection.

To add Access Control to a Collection, use the `access` property in your [Collection Config](../configuration/collections):

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

export const CollectionWithAccessControl: CollectionConfig = {
  // ...
  access: {
    // highlight-line
    // ...
  },
}
```

## Config Options

Access Control is specific to the operation of the request.

To add Access Control to a Collection, use the `access` property in your [Collection Config](../configuration/collections):

```ts
import type { CollectionConfig } from 'payload';

export const CollectionWithAccessControl: CollectionConfig = {
  // ...
  // highlight-start
  access: {
    create: () => {...},
    read: () => {...},
    update: () => {...},
    delete: () => {...},

    // Auth-enabled Collections only
    admin: () => {...},
    unlock: () => {...},

    // Version-enabled Collections only
    readVersions: () => {...},
  },
  // highlight-end
}
```

The following options are available:

| Function     | Allows/Denies Access                                                 |
| ------------ | -------------------------------------------------------------------- |
| **`create`** | Used in the `create` operation. [More details](#create).             |
| **`read`**   | Used in the `find` and `findByID` operations. [More details](#read). |
| **`update`** | Used in the `update` operation. [More details](#update).             |
| **`delete`** | Used in the `delete` operation. [More details](#delete).             |

If a Collection supports [`Authentication`](../authentication/overview), the following additional options are available:

| Function     | Allows/Denies Access                                                                     |
| ------------ | ---------------------------------------------------------------------------------------- |
| **`admin`**  | Used to restrict access to the [Admin Panel](../admin/overview). [More details](#admin). |
| **`unlock`** | Used to restrict which users can access the `unlock` operation. [More details](#unlock). |

If a Collection supports [Versions](../versions/overview), the following additional options are available:

| Function           | Allows/Denies Access                                                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`readVersions`** | Used to control who can read versions, and who can't. Will automatically restrict the Admin UI version viewing access. [More details](#read-versions). |

### Create

Returns a boolean which allows/denies access to the `create` request.

To add create Access Control to a Collection, use the `create` property in the [Collection Config](../configuration/collections):

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

export const CollectionWithCreateAccess: CollectionConfig = {
  // ...
  access: {
    // highlight-start
    create: ({ req: { user }, data }) => {
      return Boolean(user)
    },
    // highlight-end
  },
}
```

The following arguments are provided to the `create` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`data`** | The data passed to create the document with.                                                                                  |
| **`slug`** | The slug of the Collection being accessed.                                                                                    |

### Read

Returns a boolean which allows/denies access to the `read` request.

To add read Access Control to a Collection, use the `read` property in the [Collection Config](../configuration/collections):

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

export const CollectionWithReadAccess: CollectionConfig = {
  // ...
  access: {
    // highlight-start
    read: ({ req: { user } }) => {
      return Boolean(user)
    },
    // highlight-end
  },
}
```


  **Tip:** Return a [Query](../queries/overview) to limit the Documents to only
  those that match the constraint. This can be helpful to restrict users' access
  to specific Documents. [More details](../queries/overview).


As your application becomes more complex, you may want to define your function in a separate file and import them into your Collection Config:

```ts
import type { Access } from 'payload'
import type { Page } from '@/payload-types'

export const canReadPage: Access = ({ req: { user } }) => {
  // Allow authenticated users
  if (user) {
    return true
  }

  // By returning a Query, guest users can read public Documents
  // Note: this assumes you have a `isPublic` checkbox field on your Collection
  return {
    isPublic: {
      equals: true,
    },
  }
}
```

The following arguments are provided to the `read` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`id`**   | `id` of document requested, if within `findByID`.                                                                             |
| **`slug`** | The slug of the Collection being accessed.                                                                                    |

### Update

Returns a boolean which allows/denies access to the `update` request.

To add update Access Control to a Collection, use the `update` property in the [Collection Config](../configuration/collections):

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

export const CollectionWithUpdateAccess: CollectionConfig = {
  // ...
  access: {
    // highlight-start
    update: ({ req: { user } }) => {
      return Boolean(user)
    },
    // highlight-end
  },
}
```


  **Tip:** Return a [Query](../queries/overview) to limit the Documents to only
  those that match the constraint. This can be helpful to restrict users' access
  to specific Documents. [More details](../queries/overview).


As your application becomes more complex, you may want to define your function in a separate file and import them into your Collection Config:

```ts
import type { Access } from 'payload'
import type { User } from '@/payload-types'

export const canUpdateUser: Access = ({ req: { user }, id }) => {
  // Allow users with a role of 'admin'
  if (user.roles && user.roles.some((role) => role === 'admin')) {
    return true
  }

  // allow any other users to update only oneself
  return user.id === id
}
```

The following arguments are provided to the `update` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`id`**   | `id` of document requested to update.                                                                                         |
| **`data`** | The data passed to update the document with.                                                                                  |
| **`slug`** | The slug of the Collection being accessed.                                                                                    |


  **Tip:** For Collections with [Drafts](../versions/drafts) enabled, you can
  use `update` access to [control who can
  publish](../versions/drafts#controlling-who-can-publish) by returning a query
  constraint on the `_status` field.


### Delete

Similarly to the Update function, returns a boolean or a [query constraint](/docs/queries/overview) to limit which documents can be deleted by which users.

To add delete Access Control to a Collection, use the `delete` property in the [Collection Config](../configuration/collections):

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

export const CollectionWithDeleteAccess: CollectionConfig = {
  // ...
  access: {
    // highlight-start
    delete: ({ req: { user } }) => {
      return Boolean(user)
    },
    // highlight-end
  },
}
```

As your application becomes more complex, you may want to define your function in a separate file and import them into your Collection Config:

```ts
import type { Access } from 'payload'
import type { Customer } from '@/payload-types'

export const canDeleteCustomer: Access<Customer> = async ({ req, id }) => {
  if (!id) {
    // allow the admin UI to show controls to delete since it is indeterminate without the `id`
    return true
  }

  // Query another Collection using the `id`
  const result = await req.payload.find({
    collection: 'contracts',
    limit: 0,
    depth: 0,
    where: {
      customer: { equals: id },
    },
  })

  return result.totalDocs === 0
}
```

The following arguments are provided to the `delete` function:

| Option     | Description                                                                                                                                                                          |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object with additional `user` property, which is the currently logged in user.                               |
| **`id`**   | `id` of document requested to delete.                                                                                                                                                |
| **`data`** | The data being set on the document. For [Trash-enabled](../trash/overview) collections, check `data.deletedAt` to differentiate between soft delete and permanent delete operations. |
| **`slug`** | The slug of the Collection being accessed.                                                                                                                                           |


  **Tip:** For Collections with [Trash](../trash/overview) enabled, you can use
  the `data` argument to allow users to soft delete (trash) documents while
  restricting permanent deletion. See [Trash Access
  Control](../trash/overview#access-control) for examples.


### Admin

If the Collection is used to access the [Admin Panel](../admin/overview#the-admin-user-collection), the `Admin` Access Control function determines whether or not the currently logged in user can access the admin UI.

To add Admin Access Control to a Collection, use the `admin` property in the [Collection Config](../configuration/collections):

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

export const CollectionWithAdminAccess: CollectionConfig = {
  // ...
  access: {
    // highlight-start
    admin: ({ req: { user } }) => {
      return Boolean(user)
    },
    // highlight-end
  },
}
```

The following arguments are provided to the `admin` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`slug`** | The slug of the Collection being accessed.                                                                                    |

### Unlock

Determines which users can [unlock](/docs/authentication/operations#unlock) other users who may be blocked from authenticating successfully due to [failing too many login attempts](/docs/authentication/overview#config-options).

To add Unlock Access Control to a Collection, use the `unlock` property in the [Collection Config](../configuration/collections):

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

export const CollectionWithUnlockAccess: CollectionConfig = {
  // ...
  access: {
    // highlight-start
    unlock: ({ req: { user } }) => {
      return Boolean(user)
    },
    // highlight-end
  },
}
```

The following arguments are provided to the `unlock` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`slug`** | The slug of the Collection being accessed.                                                                                    |

### Read Versions

If the Collection has [Versions](../versions/overview) enabled, the `readVersions` Access Control function determines whether or not the currently logged in user can access the version history of a Document.

To add Read Versions Access Control to a Collection, use the `readVersions` property in the [Collection Config](../configuration/collections):

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

export const CollectionWithVersionsAccess: CollectionConfig = {
  // ...
  access: {
    // highlight-start
    readVersions: ({ req: { user } }) => {
      return Boolean(user)
    },
    // highlight-end
  },
}
```


  **Note:** Returning a [Query](../queries/overview) will apply the constraint
  to the [`versions` collection](../versions/overview#database-impact), not the
  original Collection.


The following arguments are provided to the `readVersions` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`slug`** | The slug of the Collection being accessed.                                                                                    |

---

## File: docs/access-control/fields.mdx

---
title: Field-level Access Control
label: Fields
order: 40
desc: Field-level Access Control is specified within a field's config, and allows you to define which users can create, read or update Fields.
keywords: fields, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---

Field Access Control is [Access Control](../access-control/overview) used to restrict access to specific [Fields](../fields/overview) within a Document.

To add Access Control to a Field, use the `access` property in your [Field Config](../fields/overview):

```ts
import type { Field } from 'payload'

export const FieldWithAccessControl: Field = {
  // ...
  access: {
    // highlight-line
    // ...
  },
}
```


  **Note:** Field Access Control does not support returning
  [Query](../queries/overview) constraints like [Collection Access
  Control](./collections) does.


## Config Options

Access Control is specific to the operation of the request.

To add Access Control to a Field, use the `access` property in the [Field Config](../fields/overview):

```ts
import type { CollectionConfig } from 'payload';

export const Posts: CollectionConfig = {
  slug: 'posts',
  fields: [
    {
      name: 'title',
      type: 'text',
      // highlight-start
      access: {
        create: ({ req: { user } }) => { ... },
        read: ({ req: { user } }) => { ... },
        update: ({ req: { user } }) => { ... },
      },
      // highlight-end
    };
  ],
};
```

The following options are available:

| Function     | Purpose                                                                                                    |
| ------------ | ---------------------------------------------------------------------------------------------------------- |
| **`create`** | Allows or denies the ability to set a field's value when creating a new document. [More details](#create). |
| **`read`**   | Allows or denies the ability to read a field's value. [More details](#read).                               |
| **`update`** | Allows or denies the ability to update a field's value [More details](#update).                            |

### Create

Returns a boolean which allows or denies the ability to set a field's value when creating a new document. If `false` is returned, any passed values will be discarded.

**Available argument properties:**

| Option            | Description                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **`req`**         | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`collection`**  | The collection config that owns the field (present only for collection-owned fields).                                        |
| **`global`**      | The global config that owns the field (present only for global-owned fields).                                                |
| **`data`**        | The full data passed to create the document.                                                                                 |
| **`siblingData`** | Immediately adjacent field data passed to create the document.                                                               |
| **`blockData`**   | The nearest parent block row data when this field is inside a block.                                                         |

### Read

Returns a boolean which allows or denies the ability to read a field's value. If `false`, the entire property is omitted from the resulting document.

**Available argument properties:**

| Option            | Description                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **`req`**         | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`collection`**  | The collection config that owns the field (present only for collection-owned fields).                                        |
| **`global`**      | The global config that owns the field (present only for global-owned fields).                                                |
| **`id`**          | `id` of the document being read                                                                                              |
| **`doc`**         | The full document data.                                                                                                      |
| **`siblingData`** | Immediately adjacent field data of the document being read.                                                                  |
| **`blockData`**   | The nearest parent block row data when this field is inside a block.                                                         |

### Update

Returns a boolean which allows or denies the ability to update a field's value. If `false` is returned, any passed values will be discarded.

If `false` is returned and you attempt to update the field's value, the operation will **not** throw an error however the field will be omitted from the update operation and the value will remain unchanged.

**Available argument properties:**

| Option            | Description                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **`req`**         | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`collection`**  | The collection config that owns the field (present only for collection-owned fields).                                        |
| **`global`**      | The global config that owns the field (present only for global-owned fields).                                                |
| **`id`**          | `id` of the document being updated                                                                                           |
| **`data`**        | The full data passed to update the document.                                                                                 |
| **`siblingData`** | Immediately adjacent field data passed to update the document with.                                                          |
| **`doc`**         | The full document data, before the update is applied.                                                                        |
| **`blockData`**   | The nearest parent block row data when this field is inside a block.                                                         |

---

## File: docs/access-control/globals.mdx

---
title: Globals Access Control
label: Globals
order: 30
desc: Global-level Access Control is specified within each Global's `access` property and allows you to define which users can read or update Globals.
keywords: globals, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---

Global Access Control is [Access Control](../access-control/overview) used to restrict access to [Global](../configuration/globals) Documents, as well as what they can and cannot see within the [Admin Panel](../admin/overview) as it relates to that Global.

To add Access Control to a Global, use the `access` property in your [Global Config](../configuration/globals):

```ts
import type { GlobalConfig } from 'payload'

export const GlobalWithAccessControl: GlobalConfig = {
  // ...
  access: {
    // highlight-line
    // ...
  },
}
```

## Config Options

Access Control is specific to the operation of the request.

To add Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../configuration/globals):

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

const GlobalWithAccessControl: GlobalConfig = {
  // ...
  // highlight-start
  access: {
    read: ({ req: { user } }) => {...},
    update: ({ req: { user } }) => {...},

    // Version-enabled Globals only
    readVersions: () => {...},
  },
  // highlight-end
}

export default Header
```

The following options are available:

| Function     | Allows/Denies Access                                            |
| ------------ | --------------------------------------------------------------- |
| **`read`**   | Used in the `findOne` Global operation. [More details](#read).  |
| **`update`** | Used in the `update` Global operation. [More details](#update). |

If a Global supports [Versions](../versions/overview), the following additional options are available:

| Function           | Allows/Denies Access                                                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`readVersions`** | Used to control who can read versions, and who can't. Will automatically restrict the Admin UI version viewing access. [More details](#read-versions). |

### Read

Returns a boolean result or optionally a [query constraint](../queries/overview) which limits who can read this global based on its current properties.

To add read Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../configuration/globals):

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

const Header: GlobalConfig = {
  // ...
  // highlight-start
  access: {
    read: ({ req: { user } }) => {
      return Boolean(user)
    },
  },
  // highlight-end
}
```

The following arguments are provided to the `read` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`slug`** | The slug of the Global being accessed.                                                                                        |

### Update

Returns a boolean result or optionally a [query constraint](../queries/overview) which limits who can update this global based on its current properties.

To add update Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../configuration/globals):

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

const Header: GlobalConfig = {
  // ...
  // highlight-start
  access: {
    update: ({ req: { user }, data }) => {
      return Boolean(user)
    },
  },
  // highlight-end
}
```

The following arguments are provided to the `update` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`data`** | The data passed to update the global with.                                                                                    |
| **`slug`** | The slug of the Global being accessed.                                                                                        |

### Read Versions

If the Global has [Versions](../versions/overview) enabled, the `readVersions` Access Control function determines whether or not the currently logged in user can access the version history of a Document.

To add Read Versions Access Control to a Global, use the `readVersions` property in the [Global Config](../configuration/globals):

```ts
import type { GlobalConfig } from 'payload'

export const GlobalWithVersionsAccess: GlobalConfig = {
  // ...
  access: {
    // highlight-start
    readVersions: ({ req: { user } }) => {
      return Boolean(user)
    },
    // highlight-end
  },
}
```


  **Note:** Returning a [Query](../queries/overview) will apply the constraint
  to the [`versions` collection](../versions/overview#database-impact), not the
  original Global.


The following arguments are provided to the `readVersions` function:

| Option     | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`req`**  | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`slug`** | The slug of the Global being accessed.                                                                                        |

---

## File: docs/access-control/overview.mdx

---
title: Access Control
label: Overview
order: 10
desc: Payload makes it simple to define and manage access control. By declaring roles, you can set permissions and restrict what your users can interact with.
keywords: overview, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, express
---

Access control within Payload is extremely powerful while remaining easy and intuitive to manage. Declaring who should have access to what documents is no more complex than writing a simple JavaScript function that either returns a `boolean` or a [`query`](/docs/queries/overview) constraint to restrict which documents users can interact with.

<YouTube
  id="DoPLyXG26Dg"
  title="Overview of Payload Access Control"
/>

**Example use cases:**

- Allowing anyone `read` access to all `Post`s
- Only allowing public access to `Post`s where a `status` field is equal to `published`
- Giving only `User`s with a `role` field equal to `admin` the ability to delete `Page`(s)
- Allowing anyone to create `ContactSubmission`s, but only logged in users to `read`, `update` or `delete` them
- Restricting a `User` to only be able to see their own `Order`(s), but no others
- Allowing `User`s that belong to a certain `Organization` to access only that `Organization`'s `Resource`s

### Default Settings

**By default, all Collections and Globals require that a user is logged in to be able to interact in any way.** The default Access Control function evaluates the `user` from the Express `req` and returns `true` if a user is logged in, and `false` if not.

**Default Access function:**

```ts
const defaultPayloadAccess = ({ req: { user } }) => {
  // Return `true` if a user is found
  // and `false` if it is undefined or null
  return Boolean(user);
}
```


  **Note:**
  In the Local API, all Access Control functions are skipped by default, allowing your server to do whatever it needs. But, you can opt back in by setting the option **overrideAccess** to **false**.


### Access Control Types

You can manage access within Payload on three different levels:

- [Collections](/docs/access-control/collections)
- [Fields](/docs/access-control/fields)
- [Globals](/docs/access-control/globals)


### When Access Control is Executed


  **Note:**
  Access control functions are utilized in two places. It's important to understand how and when your access control is executed.


#### As you execute operations

When you perform Payload operations like `create`, `read`, `update`, and `delete`, your access control functions will be executed before any changes or operations are completed.

#### Within the Admin UI

The Payload Admin UI responds dynamically to the access control that you define. For example, if you restrict editing a `ExampleCollection` to only users that feature a `role` of `admin`, the Payload Admin UI will **hide** the `ExampleCollection` from the Admin UI entirely. This is super powerful and allows you to control who can do what with your Admin UI.

To accomplish this, Payload ships with an `Access` operation, which is executed when a user logs into the Admin UI. Payload will execute each one of your access control functions, across all collections, globals, and fields, at the top level and return a response that contains a reflection of what the currently authenticated user can do with your application.

### Argument Availability


  **Important:**
  When your access control functions are executed via the **access** operation, the **id** and **data** arguments will be **undefined**, because Payload is executing your functions without referencing a specific document.


If you use `id` or `data` within your access control functions, make sure to check that they are defined first. If they are not, then you can assume that your access control is being executed via the `access` operation, to determine solely what the user can do within the Admin UI.

---

## File: docs/admin/locked-documents.mdx

---
title: Document Locking
label: Document Locking
order: 40
desc: Ensure your documents are locked during editing to prevent concurrent changes from multiple users and maintain data integrity.
keywords: locking, document locking, edit locking, document, concurrency, Payload, headless, Content Management System, cms, javascript, react, node, nextjs
---

Document locking in Payload ensures that only one user at a time can edit a document, preventing data conflicts and accidental overwrites. When a document is locked, other users are prevented from making changes until the lock is released, ensuring data integrity in collaborative environments.

The lock is automatically triggered when a user begins editing a document within the Admin Panel and remains in place until the user exits the editing view or the lock expires due to inactivity.

## How it works

When a user starts editing a document, Payload locks it for that user. If another user attempts to access the same document, they will be notified that it is currently being edited. They can then choose one of the following options:

- View in Read-Only: View the document without the ability to make any changes.
- Take Over: Take over editing from the current user, which locks the document for the new editor and notifies the original user.
- Return to Dashboard: Navigate away from the locked document and continue with other tasks.

The lock will automatically expire after a set period of inactivity, configurable using the `duration` property in the `lockDocuments` configuration, after which others can resume editing.


  **Note:** If your application does not require document locking, you can
  disable this feature for any collection or global by setting the
  `lockDocuments` property to `false`.


### Config Options

The `lockDocuments` property exists on both the Collection Config and the Global Config. Document locking is enabled by default, but you can customize the lock duration or turn off the feature for any collection or global.

Here's an example configuration for document locking:

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

export const Posts: CollectionConfig = {
  slug: 'posts',
  fields: [
    {
      name: 'title',
      type: 'text',
    },
    // other fields...
  ],
  lockDocuments: {
    duration: 600, // Duration in seconds
  },
}
```

#### Locking Options

| Option              | Description                                                                                                                                                                    |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`lockDocuments`** | Enables or disables document locking for the collection or global. By default, document locking is enabled. Set to an object to configure, or set to false to disable locking. |
| **`duration`**      | Specifies the duration (in seconds) for how long a document remains locked without user interaction. The default is 300 seconds (5 minutes).                                   |

### Impact on APIs

Document locking affects both the Local and REST APIs, ensuring that if a document is locked, concurrent users will not be able to perform updates or deletes on that document (including globals). If a user attempts to update or delete a locked document, they will receive an error.

Once the document is unlocked or the lock duration has expired, other users can proceed with updates or deletes as normal.

#### Overriding Locks

For operations like `update` and `delete`, Payload includes an `overrideLock` option. This boolean flag, when set to `false`, enforces document locks, ensuring that the operation will not proceed if another user currently holds the lock.

By default, `overrideLock` is set to `true`, which means that document locks are ignored, and the operation will proceed even if the document is locked. To enforce locks and prevent updates or deletes on locked documents, set `overrideLock: false`.

```ts
const result = await payload.update({
  collection: 'posts',
  id: '123',
  data: {
    title: 'New title',
  },
  overrideLock: false, // Enforces the document lock, preventing updates if the document is locked
})
```

This option is particularly useful in scenarios where administrative privileges or specific workflows require you to override the lock and ensure the operation is completed.

---

## File: docs/admin/metadata.mdx

---
title: Page Metadata
label: Metadata
order: 70
desc: Customize the metadata of your pages within the Admin Panel
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---

Every page within the Admin Panel automatically receives dynamic, auto-generated metadata derived from live document data, the user's current locale, and more. This includes the page title, description, og:image, etc. and requires no additional configuration.

Metadata is fully configurable at the root level and cascades down to individual collections, documents, and custom views. This allows for the ability to control metadata on any page with high precision, while also providing sensible defaults.

All metadata is injected into Next.js' [`generateMetadata`](https://nextjs.org/docs/app/api-reference/functions/generate-metadata) function. This is used to generate the `<head>` of pages within the Admin Panel. All metadata options that are available in Next.js are exposed by Payload.

Within the Admin Panel, metadata can be customized at the following levels:

- [Root Metadata](#root-metadata)
- [Collection Metadata](#collection-metadata)
- [Global Metadata](#global-metadata)
- [View Metadata](#view-metadata)

All of these types of metadata share a similar structure, with a few key differences on the Root level. To customize metadata, consult the list of available scopes. Determine the scope that corresponds to what you are trying to accomplish, then author your metadata within the Payload Config accordingly.

## Root Metadata

Root Metadata is the metadata that is applied to all pages within the Admin Panel. This is where you can control things like the suffix appended onto each page's title, the favicon displayed in the browser's tab, and the Open Graph data that is used when sharing the Admin Panel on social media.

To customize Root Metadata, use the `admin.meta` key in your Payload Config:

```ts
{
  // ...
  admin: {
    // highlight-start
    meta: {
    // highlight-end
      title: 'My Admin Panel',
      icons: [
        {
          rel: 'icon',
          type: 'image/png',
          url: '/favicon.png',
        },
      ],
    },
  },
}
```

The following options are available for Root Metadata:

| Key                  | Type                                    | Description                                                                                                                                                                                                                                                               |
| -------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultOGImageType` | `dynamic` (default), `static`, or `off` | The type of default OG image to use. If set to `dynamic`, Payload will use Next.js image generation to create an image with the title of the page. If set to `static`, Payload will use the `defaultOGImage` URL. If set to `off`, Payload will not generate an OG image. |
| `titleSuffix`        | `string`                                | A suffix to append to the end of the title of every page. Defaults to "- Payload".                                                                                                                                                                                        |
| `[keyof Metadata]`   | `unknown`                               | Any other properties that Next.js supports within the `generateMetadata` function. [More details](https://nextjs.org/docs/app/api-reference/functions/generate-metadata).                                                                                                 |


  **Reminder:** These are the _root-level_ options for the Admin Panel. You can
  also customize metadata on the [Collection](../configuration/collections),
  [Global](../configuration/globals), and Document levels through their
  respective configs.


### Icons

The Icons Config corresponds to the `<link>` tags that are used to specify icons for the Admin Panel. The `icons` key is an array of objects, each of which represents an individual icon. Icons are differentiated from one another by their `rel` attribute, which specifies the relationship between the document and the icon.

The most common icon type is the favicon, which is displayed in the browser tab. This is specified by the `rel` attribute `icon`. Other common icon types include `apple-touch-icon`, which is used by Apple devices when the Admin Panel is saved to the home screen, and `mask-icon`, which is used by Safari to mask the Admin Panel icon.

To customize icons, use the `admin.meta.icons` property in your Payload Config:

```ts
{
  // ...
  admin: {
    meta: {
      // highlight-start
      icons: [
      // highlight-end
        {
          rel: 'icon',
          type: 'image/png',
          url: '/favicon.png',
        },
        {
          rel: 'apple-touch-icon',
          type: 'image/png',
          url: '/apple-touch-icon.png',
        },
      ],
    },
  },
}
```

For a full list of all available Icon options, see the [Next.js documentation](https://nextjs.org/docs/app/api-reference/functions/generate-metadata#icons).

### Open Graph

Open Graph metadata is a set of tags that are used to control how URLs are displayed when shared on social media platforms. Open Graph metadata is automatically generated by Payload, but can be customized at the Root level.

To customize Open Graph metadata, use the `admin.meta.openGraph` property in your Payload Config:

```ts
{
  // ...
  admin: {
    meta: {
      // highlight-start
      openGraph: {
      // highlight-end
        images: [
          {
            url: 'https://example.com/image.jpg',
            width: 800,
            height: 600,
          },
        ],
        siteName: 'Payload',
        title: 'My Admin Panel',
      },
    },
  },
}
```

For a full list of all available Open Graph options, see the [Next.js documentation](https://nextjs.org/docs/app/api-reference/functions/generate-metadata#opengraph).

### Robots

Setting the `robots` property will allow you to control the `robots` meta tag that is rendered within the `<head>` of the Admin Panel. This can be used to control how search engines index pages and displays them in search results.

By default, the Admin Panel is set to prevent search engines from indexing pages within the Admin Panel.

To customize the Robots Config, use the `admin.meta.robots` property in your Payload Config:

```ts
{
  // ...
  admin: {
    meta: {
      // highlight-start
      robots: 'noindex, nofollow',
      // highlight-end
    },
  },
}
```

For a full list of all available Robots options, see the [Next.js documentation](https://nextjs.org/docs/app/api-reference/functions/generate-metadata#robots).

##### Prevent Crawling

While setting meta tags via `admin.meta.robots` can prevent search engines from _indexing_ web pages, it does not prevent them from being _crawled_.

To prevent your pages from being crawled altogether, add a `robots.txt` file to your root directory.

```text
User-agent: *
Disallow: /admin/
```


  **Note:** If you've customized the path to your Admin Panel via
  `config.routes`, be sure to update the `Disallow` directive to match your
  custom path.


## Collection Metadata

Collection Metadata is the metadata that is applied to all pages within any given Collection within the Admin Panel. This metadata is used to customize the title and description of all views within any given Collection, unless overridden by the view itself.

To customize Collection Metadata, use the `admin.meta` key within your Collection Config:

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

export const MyCollection: CollectionConfig = {
  // ...
  admin: {
    // highlight-start
    meta: {
      // highlight-end
      title: 'My Collection',
    },
  },
}
```

The Collection Meta config has the same options as the [Root Metadata](#root-metadata) config.

## Global Metadata

Global Metadata is the metadata that is applied to all pages within any given Global within the Admin Panel. This metadata is used to customize the title and description of all views within any given Global, unless overridden by the view itself.

To customize Global Metadata, use the `admin.meta` key within your Global Config:

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

export const MyGlobal: GlobalConfig = {
  // ...
  admin: {
    // highlight-start
    meta: {
      // highlight-end
      title: 'My Global',
    },
  },
}
```

The Global Meta config has the same options as the [Root Metadata](#root-metadata) config.

## View Metadata

View Metadata is the metadata that is applied to specific [Views](../custom-components/custom-views) within the Admin Panel. This metadata is used to customize the title and description of a specific view, overriding any metadata set at the [Root](#root-metadata), [Collection](#collection-metadata), or [Global](#global-metadata) level.

To customize View Metadata, use the `meta` key within your View Config:

```ts
{
  // ...
  admin: {
    views: {
      dashboard: {
        // highlight-start
        meta: {
        // highlight-end
          title: 'My Dashboard',
        }
      },
    },
  },
}
```

---

## File: docs/admin/overview.mdx

---
title: The Admin Panel
label: Overview
order: 10
desc: Manage your data and customize the Admin Panel by swapping in your own React components. Create, modify or remove views, fields, styles and much more.
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, express
---

Payload dynamically generates a beautiful, fully functional React admin panel to manage your data. It's extremely powerful and can be customized / extended upon easily by swapping in your own React components. You can add additional views, modify how built-in views look / work, swap out Payload branding for your client's, build your own field types and much more.

The Payload Admin panel is built with Webpack, code-split, highly performant (even with 100+ fields), and written fully in TypeScript.


  The Admin panel is meant to be simple enough to give you a starting point but
  not bring too much complexity, so that you can easily customize it to suit the
  needs of your application and your editors.




_Screenshot of the Admin panel while editing a document from an example `AllFields` collection_

## Admin Options

All options for the Admin panel are defined in your base Payload config file.

| Option                | Description                                                                                                                                                                                                                                                  |
|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `user`                | The `slug` of a Collection that you want be used to log in to the Admin dashboard. [More](/docs/admin/overview#the-admin-user-collection)                                                                                                                    |
| `buildPath`           | Specify an absolute path for where to store the built Admin panel bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`.                                                                                                             |
| `meta`                | Base meta data to use for the Admin panel. Included properties are `titleSuffix`, `ogImage`, and `favicon`.                                                                                                                                                  |
| `disable`             | If set to `true`, the entire Admin panel will be disabled.                                                                                                                                                                                                   |
| `indexHTML`           | Optionally replace the entirety of the `index.html` file used by the Admin panel. Reference the [base index.html file](https://github.com/payloadcms/payload/blob/master/src/admin/index.html) to ensure your replacement has the appropriate HTML elements. |
| `css`                 | Absolute path to a stylesheet that you can use to override / customize the Admin panel styling. [More](/docs/admin/customizing-css).                                                                                                                         |
| `scss`                | Absolute path to a Sass variables / mixins stylesheet meant to override Payload styles to make for an easy re-skinning of the Admin panel. [More](/docs/admin/customizing-css#overriding-scss-variables).                                                    |
| `dateFormat`          | Global date format that will be used for all dates in the Admin panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used.                                                                                                               |
| `avatar`              | Set account profile picture. Options: `gravatar`, `default` or a custom React component.                                                                                                                                                                     |
| `autoLogin`           | Used to automate admin log-in for dev and demonstration convenience. [More](/docs/authentication/config).                                                                                                                                                    |
| `components`          | Component overrides that affect the entirety of the Admin panel. [More](/docs/admin/components)                                                                                                                                                              |
| `webpack`             | Customize the Webpack config that's used to generate the Admin panel. [More](/docs/admin/webpack)                                                                                                                                                            |
| **`logoutRoute`**     | The route for the `logout` page.                                                                                                                                                                                                                             |
| **`inactivityRoute`** | The route for the `logout` inactivity page.                                                                                                                                                                                                                  |

### The Admin User Collection


  **Important:**
  
  The Payload Admin panel can only be used by one Collection that supports
  [Authentication](/docs/authentication/overview).


To specify which Collection to use to log in to the Admin panel, pass the `admin` options a `user` key equal to the slug of the Collection that you'd like to use.

`payload.config.js`:

```ts
import { buildConfig } from "payload/config";

const config = buildConfig({
  admin: {
    user: "admins", // highlight-line
  },
});
```

By default, if you have not specified a Collection, Payload will automatically provide you with a `User` Collection which will be used to access the Admin panel. You can customize or override the fields and settings of the default `User` Collection by passing your own collection using `users` as its `slug` to Payload. When this is done, Payload will use your provided `User` Collection instead of its default version.

**Note: you can use whatever Collection you'd like to access the Admin panel as long as the Collection supports Authentication. It doesn't need to be called `users`!**

For example, you may wish to have two Collections that both support `Authentication`:

- `admins` - meant to have a higher level of permissions to manage your data and access the Admin panel
- `customers` - meant for end users of your app that should not be allowed to log into the Admin panel

This is totally possible. For the above scenario, by specifying `admin: { user: 'admins' }`, your Payload Admin panel will use `admins`. Any users logged in as `customers` will not be able to log in via the Admin panel.

### Light and dark modes

Users in the admin panel have access to choosing between light mode and dark mode for their editing experience. The setting is managed while logged into the admin UI within the user account page and will be stored with the browser. By default, the operating system preference is detected and used.

### Restricting user access

If you would like to restrict which users from a single Collection can access the Admin panel, you can use the `admin` access control function. [Click here](/docs/access-control/overview#admin) to learn more.

---

## File: docs/admin/preferences.mdx

---
title: Managing User Preferences
label: Preferences
order: 50
desc: Store the preferences of your users as they interact with the Admin panel.
keywords: admin, preferences, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, express
---

As your users interact with your Admin panel, you might want to store their preferences in a persistent manner, so that when they revisit the Admin panel, they can pick right back up where they left off.

Out of the box, Payload handles the persistence of your users' preferences in a handful of ways, including:

1. Collection `List` view active columns, and their order, that users define
1. Their last active locale
1. The "collapsed" state of blocks, on a document level, as users edit or interact with documents


	**Important:**
	All preferences are stored on an individual user basis. Payload automatically recognizes the user that is reading or setting a preference via all provided authentication methods.


### Use cases

This API is used significantly for internal operations of the Admin panel, as mentioned above. But, if you're building your own React components for use in the Admin panel, you can allow users to set their own preferences in correspondence to their usage of your components. For example:

- If you have built a "color picker", you could "remember" the last used colors that the user has set for easy access next time
- If you've built a custom `Nav` component, and you've built in an "accordion-style" UI, you might want to store the `collapsed` state of each Nav collapsible item. This way, if an editor returns to the panel, their `Nav` state is persisted automatically
- You might want to store `recentlyAccessed` documents to give admin editors an easy shortcut back to their recently accessed documents on the `Dashboard` or similar
- Many other use cases exist. Invent your own! Give your editors an intelligent and persistent editing experience.

### Database

Payload automatically creates an internally used `_preferences` collection that stores user preferences. Each document in the `_preferences` collection contains the following shape:

| Key                  | Value  |
| -------------------- | -------------|
| `id`                 | A unique ID for each preference stored. |
| `key`                | A unique `key` that corresponds to the preference. |
| `user`               | The ID of the `user` that is storing its preference. |
| `userCollection`     | The `slug` of the collection that the `user` is logged in as. |
| `value`              | The value of the preference. Can be any data shape that you need. |
| `createdAt`          | A timestamp of when the preference was created. |
| `updatedAt`          | A timestamp set to the last time the preference was updated.

### APIs

Preferences are available to both [GraphQL](/docs/graphql/overview#preferences) and [REST](/docs/rest-api/overview#) APIs.

### Adding or reading Preferences in your own components

The Payload admin panel offers a `usePreferences` hook. The hook is only meant for use within the admin panel itself. It provides you with two methods:

##### `getPreference`

This async method provides an easy way to retrieve a user's preferences by `key`. It will return a promise containing the resulting preference value.

**Arguments**

- `key`: the `key` of your preference to retrieve.

##### `setPreference`

Also async, this method provides you with an easy way to set a user preference. It returns `void`.

**Arguments:**

- `key`: the `key` of your preference to set.
- `value`: the `value` of your preference that you're looking to set.

## Example

Here is an example for how you can utilize `usePreferences` within your custom Admin panel components. Note - this example is not fully useful and is more just a reference for how to utilize the Preferences API. In this case, we are demonstrating how to set and retrieve a user's last used colors history within a `ColorPicker` or similar type component.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## 2. Official Technical Reference & Guides (payloadcms/website)

# Payload Website

This is the repository for [Payload's official website](https://payloadcms.com/). It was built completely in public using Payload itself, [more on that here](#⭐-the-cms).



This site showcases lots of cool stuff like how to use Next.js 15 + Payload's local API to its fullest extent, how to build a super dynamic light / dark mode into a Next site without any first-load flickering, how to render remotely stored docs from MDX to Next.js pages using just Payload (no external libraries), how to use Stripe to build a custom SaaS integration, and much more.

## ✨ Tech stack

- [Payload](https://github.com/payloadcms/payload) (obviously)
- TypeScript
- Next.js 15 and its new App Router
- SCSS Modules
- MDX for docs, using the [Lexical MDX Converter](https://payloadcms.com/docs/rich-text/converting-markdown#converting-mdx)
- GraphQL for Payload Cloud
- Stripe for Payload Cloud

## ⭐ The CMS

[Payload](https://github.com/payloadcms/payload) is leveraged for everything that this site does, outside of its documentation which is all stored as Markdown in the Payload repo on GitHub. Both the CMS and the website frontend are found within the same app folder.

## ☁️ Payload Cloud

This repo contains the source code for [Payload Cloud](https://payloadcms.com/cloud-pricing). This is a one-click integration to deploy production-ready instances of your Payload apps directly from your GitHub repo, [read the blog post](https://payloadcms.com/blog/launch-week-day-1-payload-cloud-is-here) to get all the details. The entire frontend of Payload Cloud has been built in public and is included within this repo 😱.

## 🚀 Running the project locally

To get started with this repo locally, follow the steps below:

- Clone the repo
- `pnpm i`
- Run `cp .env.example .env` to create an `.env` file
- Fill out the values within your new `.env`, corresponding to your own environment
- Run `pnpm dev`
- Bam

### Hosts file

The locally running app must run on `local.payloadcms.com:3000` because of http-only cookie policies and how the GitHub App redirects the user back to the site after authenticating. To do this, you'll need to add the following to your hosts file:

```env
127.0.0.1 local.payloadcms.com
```

> On Mac you can find the hosts file at `/etc/hosts`. On Windows, it's at `C:\Windows\System32\drivers\etc\hosts`:

### Documentation

The documentation for this site is stored in the [Payload repo](https://github.com/payloadcms/payload) as Markdown files. These are fetched when you press the "Sync Docs" button in the CMS. Pressing that button does the following:

1. Docs are pulled from the Payload repo on GitHub.
2. The docs are converted from MDX to Lexical and stored in the CMS.
3. The frontend docs pages are revalidated.
4. Visiting the docs pages will pull the latest docs from the CMS, and render those lexical nodes to JSX.

#### Working on the docs locally - GitHub

By default, the docs are pulled from the `main` branch of the Payload repo on GitHub. You can **load the docs** for a different branch by opening the /docs/dynamic/ route on the website. This will dynamically load them every time you visit the page, without needing to sync them in the CMS.

Example:

- This pulls from the main branch: https://payloadcms.com/docs/getting-started/concepts
- This pulls from the feat/myfeature branch: https://payloadcms.com/docs/dynamic/getting-started/concepts?branch=feat/myfeature

In order to edit docs for that branch without touching markdown files, you can use the branch selector in the CMS to select the branch you want to work on. After making changes and saving the document, the lexical docs will be converted to MDX and pushed to the selected branch on GitHub.

You will need to set the following environment variables to work with the GitHub sync:

```env
// .env
# For reading from GitHub
GITHUB_ACCESS_TOKEN=ghp_
GITHUB_CLIENT_SECRET=
# For writing to GitHub - you can run the https://github.com/payloadcms/gh-commit repo locally
COMMIT_DOCS_API_URL=
COMMIT_DOCS_API_KEY=
```

#### Working on docs locally - local markdown files

If you have the docs stored locally as markdown files and would like to preview them in the website, you can use the /docs/local/ route in the website. First, you need to set the `DOCS_DIR_V3` environment variable to point to your local `docs` directory.

```env
// .env
DOCS_DIR_V3=/documents/github/payload/docs
```

Then, just open the `/docs/local/` route: http://localhost:3000/docs/local/getting-started/concepts.

Every time you make a change to the markdown files, just reload the page to see the changes reflected. The local MDX files are read, automatically converted to lexical on-the-fly, and rendered in the website. This process will not make any changes to the database.

#### Beta and Legacy environment flags

You can also specify a `beta` version and `legacy` version to render different versions of the docs:

- Set the environment variable `NEXT_PUBLIC_ENABLE_BETA_DOCS` to `true` to enable the beta docs.
- Specify a branch, commit, or tag with `NEXT_PUBLIC_BETA_DOCS_REF`. The default for the beta docs is `beta`.
- Set the environment variable `NEXT_PUBLIC_ENABLE_LEGACY_DOCS` to `true` to enable the legacy docs.
- Specify a branch, commit, or tag with `NEXT_PUBLIC_LEGACY_DOCS_REF`. The default for the legacy docs is `null`, and will fallback to the `main` branch.

### License

The Payload website is available as open source under the terms of the [MIT license](https://github.com/payloadcms/website/blob/main/LICENSE).