docs/plugins/overview.mdx
Payload Plugins take full advantage of the modularity of the Payload Config, allowing developers to easily inject custom—sometimes complex—functionality into Payload apps from a very small touch-point. This is especially useful for sharing your work across multiple projects or with the greater Payload community.
There are many Official Plugins available that solve for some of the most common use cases, such as the Form Builder Plugin or SEO Plugin. There are also Community Plugins available, maintained entirely by contributing members. To extend Payload's functionality in some other way, you can easily build your own plugin.
To configure Plugins, use the plugins property in your Payload Config:
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
// highlight-start
plugins: [
// Add Plugins here
],
// highlight-end
})
Writing Plugins is no more complex than writing regular JavaScript. If you know the basic concept of callback functions or how spread syntax works, and are up to speed with Payload concepts, then writing a plugin will be a breeze.
<Banner type="success"> Because we rely on a simple config-based structure, Payload Plugins simply take in an existing config and return a _modified_ config with new fields, hooks, collections, admin views, or anything else you can think of. </Banner>Example use cases:
upload-enabled collections with a third-party file host like S3 or CloudinaryPayload maintains a set of Official Plugins that solve for some of the common use cases. These plugins are maintained by the Payload team and its contributors and are guaranteed to be stable and up-to-date.
You can also build your own plugin to easily extend Payload's functionality in some other way. Once your plugin is ready, consider sharing it with the community.
Plugins are changing every day, so be sure to check back often to see what new plugins may have been added. If you have a specific plugin you would like to see, please feel free to start a new Discussion.
<Banner type="warning"> For a complete list of Official Plugins, visit the [Packages Directory](https://github.com/payloadcms/payload/tree/3.x/packages) of the [Payload Monorepo](https://github.com/payloadcms/payload). </Banner>Community Plugins are those that are maintained entirely by outside contributors. They are a great way to share your work across the ecosystem for others to use. You can discover Community Plugins by browsing the payload-plugin topic on GitHub.
Some plugins have become so widely used that they are adopted as an Official Plugin, such as the Lexical Plugin. If you have a plugin that you think should be an Official Plugin, please feel free to start a new Discussion.
<Banner type="warning"> For maintainers building plugins for others to use, please add the `payload-plugin` topic on [GitHub](https://github.com/topics/payload-plugin) to help others find it. </Banner>The base Payload Config allows for a plugins property which takes an array of Plugin Configs.
import { buildConfig } from 'payload'
import { addLastModified } from './addLastModified.ts'
const config = buildConfig({
// ...
// highlight-start
plugins: [addLastModified],
// highlight-end
})
Here is an example what the addLastModified plugin from above might look like. It adds a lastModifiedBy field to all Payload collections. For full details, see how to build your own plugin.
import { Config, Plugin } from 'payload'
export const addLastModified: Plugin = (incomingConfig: Config): Config => {
// Find all incoming auth-enabled collections
// so we can create a lastModifiedBy relationship field
// to all auth collections
const authEnabledCollections = incomingConfig.collections.filter(
(collection) => Boolean(collection.auth),
)
// Spread the existing config
const config: Config = {
...incomingConfig,
collections: incomingConfig.collections.map((collection) => {
// Spread each item that we are modifying,
// and add our new field - complete with
// hooks and proper admin UI config
return {
...collection,
fields: [
...collection.fields,
{
name: 'lastModifiedBy',
type: 'relationship',
relationTo: authEnabledCollections.map(({ slug }) => slug),
hooks: {
beforeChange: [
({ req }) => ({
value: req?.user?.id,
relationTo: req?.user?.collection,
}),
],
},
admin: {
position: 'sidebar',
readOnly: true,
},
},
],
}
}),
}
return config
}