Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

New in Payload: Admin, Rich Text, and Extensibility

Release Roundup May
Release Roundup May

v3.76 through v3.84 is one of our strongest extensibility pushes yet — configurable dashboard widgets, fully custom collection views built with client components, a more powerful plugin API, and smarter query management for editorial teams.

Widget fields with configuration UI — v3.78

Building on the dashboard widget system, Payload now supports widgets with their own editable settings. Editors can configure widget behavior directly from the admin panel without any code changes. This makes dashboards genuinely dynamic — not just developer-configured at build time.

1
// payload.config.ts
2
export default buildConfig({
3
admin: {
4
dashboard: {
5
widgets: [
6
{
7
slug: "recent-activity",
8
Component: "@/components/widgets/RecentActivityWidget",
9
label: "Recent Activity",
10
// Fields editors can configure from the admin panel
11
fields: [
12
{
13
name: "limit",
14
type: "number",
15
defaultValue: 10,
16
label: "Number of items to show",
17
},
18
{
19
name: "collection",
20
type: "select",
21
options: ["posts", "orders", "users"],
22
label: "Collection to watch",
23
},
24
],
25
},
26
],
27
},
28
},
29
});
1
// components/widgets/RecentActivityWidget.tsx
2
"use client";
3
4
type Props = {
5
data: {
6
limit: number;
7
collection: string;
8
};
9
};
10
11
export default function RecentActivityWidget({ data }: Props) {
12
return (
13
<div>
14
<h3>
15
Recent {data.collection} (last {data.limit})
16
</h3>
17
{/* fetch and render using data.collection and data.limit */}
18
</div>
19
);
20
}

Client components as custom collection views — v3.84

You can now use client-side React components as fully custom views for any collection. This unlocks rich, interactive admin experiences — custom tables, drag-and-drop interfaces, data dashboards — all within the Payload admin. It's one of the biggest steps forward for teams who need the admin to feel like a purpose-built tool rather than a generic CMS.

1
// collections/Products.ts
2
export const Products: CollectionConfig = {
3
slug: "products",
4
admin: {
5
components: {
6
views: {
7
// Override the default list view entirely
8
list: {
9
Component: "@/components/admin/ProductGridView",
10
},
11
// Add a custom view at /admin/collections/products/analytics
12
analytics: {
13
path: "/analytics",
14
Component: "@/components/admin/ProductAnalyticsView",
15
},
16
},
17
},
18
},
19
};
1
// components/admin/ProductGridView.tsx
2
"use client";
3
4
import { useListQuery } from "@payloadcms/ui";
5
6
export default function ProductGridView() {
7
const { data } = useListQuery();
8
9
return (
10
<div
11
style={{
12
display: "grid",
13
gridTemplateColumns: "repeat(3, 1fr)",
14
gap: 16,
15
}}
16
>
17
{data?.docs.map((product) => (
18
<div key={product.id}>
19
<img src={product.image?.url} alt={product.title} />
20
<h3>{product.title}</h3>
21
</div>
22
))}
23
</div>
24
);
25
}

Expanded plugin API — v3.83

The plugin system received a significant upgrade: plugins can now declare execution order, discover other registered plugins by slug, and assign priority values. This makes it possible to build plugins that coordinate intelligently with each other without relying on fragile load-order assumptions.

1
import { definePlugin } from "payload";
2
3
export const myPlugin = definePlugin({
4
slug: "my-analytics-plugin",
5
// Lower order runs first — defaults to 0
6
order: 10,
7
plugin: (incomingConfig) => {
8
return {
9
...incomingConfig,
10
collections: [...(incomingConfig.collections || []), AnalyticsCollection],
11
};
12
},
13
});
14
15
// Another plugin that depends on the above
16
export const myDashboardPlugin = definePlugin({
17
slug: "my-dashboard-plugin",
18
order: 20, // Runs after my-analytics-plugin
19
plugin: (incomingConfig) => {
20
// Discover the analytics plugin
21
const analyticsPlugin = incomingConfig.plugins?.find(
22
(p) => (p as any).slug === "my-analytics-plugin",
23
);
24
return {
25
...incomingConfig,
26
// configure based on whether analytics is present
27
};
28
},
29
});

Editable query presets — v3.78

Query presets let teams save and reuse filter configurations as named views on collection list pages. In v3.78, these became editable directly from the document form view — meaning editors can create and manage their saved filters without navigating back to the list. If your team works with complex filter combinations regularly, this removes a lot of repetitive setup.