Skip to content

Releases: payloadcms/payload

v3.83.0

15 Apr 18:58
474eda2

Choose a tag to compare

v3.83.0 (2026-04-15)

🚀 Features

  • expand plugin API (#16247) (54189e1)
  • add profiling utilities for performance analysis (#16198) (9391c20)
  • add internal plugin priority and slug api for cross-plugin discovery (#16244) (5f5694f)
  • hide slug field buttons when field is read-only (#14824) (67c2c47)
  • cpa: add --agent flag for coding agent skill installation (#16278) (9f9f343)
  • drizzle: add uuidv7 support (#16113) (ac01e82)
  • email-resend: add Custom headers for the Resend adapter (#15645) (a7dd17c)
  • next: add support for custom collection views (#16243) (835a0ad)
  • plugin-form-builder: change checkbox label from 'Default Value' to 'Checked by default' (#15229) (b3d2054)
  • plugin-mcp: allow external plugins to extend mcp plugin (#16245) (ac4fc31)
  • richtext-lexical: add view override system for custom node rendering (#14244) (1ef43eb)
  • storage-*: add useCompositePrefixes option and fix client upload prefix handling (#16230) (74aa825)

Expanded Plugin API — New definePlugin helper introduces opt-in execution ordering, cross-plugin discovery via a slug-keyed plugins map, and module augmentation for type-safe plugin options. The existing (config) => config contract remains unchanged. #16247

import { definePlugin } from 'payload'

export const seoPlugin = definePlugin<SEOPluginOptions>({
  slug: 'plugin-seo',
  order: 10,
  plugin: ({ config, plugins, collections, generateTitle }) => ({
    ...config,
    // collections and generateTitle come from SEOPluginOptions
  }),
})

Profiling Utilities — Lightweight timeSync and timeAsync wrappers for measuring function execution time during development. Wrap any function to capture its duration, then call printProfileResults for a formatted timing table. Not intended for production use. #16198

Internal Plugin Priority & Slug API — Plugins can now attach priority, slug, and options properties for execution ordering and cross-plugin discovery. Lower priority runs first; other plugins can find each other by slug via config.plugins without imports. Marked @internal for now. #16244

Hidden Slug Field Buttons on Read-Only — The Generate and Lock/Unlock buttons on slug fields are now automatically hidden when the field is read-only, removing controls that serve no purpose in that state. #14824

Agent Flag for CPA (cpa)create-payload-app now supports a --agent / -a flag (claude, codex, cursor) that downloads the Payload coding skill from GitHub and installs it in the correct directory for your agent. A root-level CLAUDE.md or AGENTS.md is written for discoverability. Use --no-agent to skip. #16278

CPA agent selection prompt

UUIDv7 Support (drizzle) — New idType: 'uuidv7' option for Postgres and SQLite adapters generates time-ordered UUIDs that are friendlier for B-tree indexes than random v4 UUIDs, while using the same storage column type. IDs are generated in application code so older Postgres versions are supported. #16113

Custom Email Headers (email-resend) — The Resend adapter now passes custom headers from sendEmail options to the Resend API, enabling features like List-Unsubscribe headers that were previously silently dropped. #15645

await payload.sendEmail({
  from: "Test <test@domain.com>",
  to: "jimmybillbob@example.com",
  subject: "Email with custom headers",
  html: html,
  headers: {
    "List-Unsubscribe": "<https://domain.com/unsubscribe>",
    "List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
  },
});

Custom Collection Views (next) — Register custom views at the collection level via admin.components.views[key] with a Component and path. Folders take routing precedence over custom views on upload collections. #16243

{
  slug: 'products',
  admin: {
    components: {
      views: {
        grid: {
          Component: '/components/GridView',
          path: '/grid',
          exact: true,
        },
      },
    },
  },
}

Checkbox Label Clarity (plugin-form-builder) — The form builder checkbox field label was changed from "Default Value" to "Checked by default" to eliminate confusion about whether the checkbox toggles a default value or sets the initial checked state. #15229

Extensible MCP Plugin (plugin-mcp) — External plugins can now extend plugin-mcp by finding it via slug in config.plugins and injecting custom MCP tools into its options. Also exports the MCPPluginConfig type for type-safe tool injection. #16245

View Override System for Custom Node Rendering (richtext-lexical)⚠️ Experimental. Override how any Lexical node type is rendered in the editor via view maps. Supports custom DOM, React components, or HTML strings. Works in both the admin editor and frontend JSX serialization for WYSIWYG consistency. #14244

export const myViews: LexicalEditorViewMap = {
  default: {
    heading: {
      createDOM() {
        const h2 = document.createElement('h2')
        h2.textContent = 'Custom Heading'
        return h2
      },
    },
    horizontalRule: {
      Component: () => <div className="custom-hr">---</div>,
    },
    link: {
      html: '<a href="#">Custom Link</a>',
    },
  },
}
{
  fields: [
    {
      name: 'content',
      type: 'richText',
      editor: lexicalEditor({
        views: '/path/to/views.tsx#myViews',
      }),
    },
  ]
}

Composite Prefixes for Storage Adapters (storage-*) — New useCompositePrefixes option combines collection and document prefixes instead of one overriding the other. Also fixes a bug where client uploads ignored document prefix entirely. Applies to S3, Azure, GCS, R2, and Vercel Blob. #16230

Mode Collection Prefix Doc Prefix Result
false (default) media-folder user-123 user-123/file.jpg
true media-folder user-123 media-folder/user-123/file.jpg

🐛 Bug Fixes

  • restore falling back to current document values for undefined fields (#16272) (4b4d61c)
  • enforce mimeTypes restriction when useTempFiles is enabled (#16255) (bb749a5)
  • prevent cron from permanently dying after handler errors (#16219) (c5e0e02)
  • use safe property assignment in deepMergeSimple (#16271) (2b23010)
  • handle concurrent autosave write conflicts gracefully (#16216) (e8502fa)
  • use instanceof instead of constructor name in formatErrors (#16089) (216d162)
  • parse JSON string where query param (#15745) (2a26b5a)
  • expose type for field's position (#14390) (d9b3c07)
  • default virtual fields to readOnly in admin UI (#16016) (72396f6)
  • localized array,group,blocks fields duplicate with empty values ([#15849](https://github....
Read more

v3.82.1

09 Apr 13:26

Choose a tag to compare

v3.82.1 (2026-04-09)

🐛 Bug Fixes

  • next: use correct config key for disabling turbo server fast refresh (#16215) (11adc9d)
  • plugin-nested-docs: await populateBreadcrumbs in resaveChildren (#15582) (0554b50)

⚡ Performance

  • storage-s3: avoid getObject call if ETag matches (#15295) (7ccc3f0)

📚 Documentation

  • fix incorrect select syntax example in querying docs (#14590) (be6c443)

📝 Templates

  • bump to 3.82.0, remove --no-server-fast-refresh flag (#16212) (79c8d7e)

🤝 Contributors

v3.82.0

08 Apr 16:06

Choose a tag to compare

v3.82.0 (2026-04-08)

🚀 Features

  • disambiguate media files by prefix via query parameter (#15844) (05ddec1)
  • add missing disableErrors to globals findOne operation (#14913) (c8332e7)
  • improve default slugify utility by triming whitespace first (#14421) (fdaa051)
  • add typescript.postProcess hook for type generation (#16103) (67b5dc3)
  • plugin-redirects: add Portuguese translation (#15269) (122f4c1)
  • plugin-search: pass collection slug to beforeSync hook (#11581) (ebbd6ad)
  • ui: export drag-and-drop components (#12626) (23b0f1b)

🐛 Bug Fixes

  • incorrect 24 hour format comment example (#15649) (f42b767)
  • resolve 404/500 error when downloading files containing hash in filename (#15799) (3a09387)
  • JSDoc string for focalPoint option in uploads so it correctly mentions defaults to true (#13070) (84090ac)
  • skip validation for unpublish operations with localized required fields (#16120) (24b9e13)
  • skip default validation for virtual fields (#16015) (e09c619)
  • db-mongodb: update mongoose-paginate-v2 to fix collation pagination (#16049) (78a27ab)
  • drizzle: convert equals/not_equals to in/not_in for hasMany relationship array values (#15766) (59af156)
  • next: fix hmr, bump minimum required next.js 16 version to 16.2.2 (#16202) (7f83571)
  • next: admin.meta.title object form renders [object Object] in browser tab (#16117) (0981cdc)
  • plugin-mcp: add error handling to convertCollectionSchemaToZod (#16114) (6184b0c)
  • plugin-multi-tenant: infinite api calling loop on user switch (#16065) (3da805f)
  • storage-*: redundant re-uploads when file was already uploaded by the client and add comprehensive E2E tests for s3 and vercel-blob (#16115) (a6735f3)
  • storage-azure: fix azure storage mime type handling for streaming uploads (#15949) (cd7fcea)
  • templates: tailwind file extension is wrong in website template components.json file (#9342) (2011f28)
  • templates: fixed forgot password link (#15037) (b505e36)
  • templates: add generated files to ESLint ignores (#15716) (941a41f)
  • templates: typo in with-cloudflare-d1 template (#14243) (14b708f)
  • translations: fix Swedish unpublish translations and capitalization (#15353) (4e48706)
  • translations: correct French translation for 'move' action (#14771) (750d29f)
  • translations: update passive voice and newLabel wording in zh-TW translations (#13761) (e284ab5)
  • translations: update Japanese translations related to localizeStatus (#15358) (7ab2881)
  • ui: relationship filter duplicate options when switching operators (#16204) (3a1f31a)
  • ui: unpublish button missing for globals and version count incorrectly incrementing after unpublish (#16203) (1ddeb60)
  • ui: exclude unnamed tab labels from filter and groupBy field options (#9965) (b13c5c9)
  • ui: update node to v20 (#15717) (b2593d6)
  • ui: radio fields do not reliably trigger admin.condition re-evaluation on sibling fields (#16056) (7e2a126)

⚡ Performance

🛠 Refactors

  • plugin-seo: rename non-JSX files from .tsx to .ts (#14418) (b67882c)
  • translations: improve German translations for consistency and accuracy (#14439) (f3c0bc8)

📚 Documentation

  • fix typo in Collection Config docs (collection → collections) (#16183) (ac085cd)
  • remove JSX comment from content in dashboard (#16156) (05447b7)
  • add warning about Cosmos dB incompatibility (#13350) (c4375bd)
  • add info about custom errors via APIError to hooks overview (#13047) (d03054e)
  • fix typo in storage-adapters documentation (#13648) (911f059)
  • rename incorrect usage of the cloud storage plugin to align with the imported module in storage-adapters.mdx (#11475) (d491f29)
  • add dev note about auth strategy hot-reload requirement (#14122) (c4da453)
  • fix anchor link reference for settingsMenu (#14391) (8c748d6)
  • nested plugin (#15230) (2e653ae)
  • add getDataByPath to useForm table (#12098) (69a49e7)
  • add missing comma to seo plugin doc (#11516) (df03ed0)
  • fix typo in ecommerce template link in seo plugin docs (#15641) (e2cd07c)
  • corrects Local API example in import export docs (#16128) (13a726a)
  • update link to Custom Components Performance docs (#15723) (9141e34)
  • update folders documentation with the right property ([#14060](https://github.com/...
Read more

v3.81.0

01 Apr 01:16

Choose a tag to compare

v3.81.0 (2026-04-01)

🚀 Features

  • add LLM eval suite for Payload conventions and code generation (#15710) (db4b00e)
  • next: prevent admin panel errors when cacheComponents is enabled (#16020) (1ecd7dd)

🐛 Bug Fixes

  • update file-type, ajv and jose packages (#16118) (d09ed54)
  • add field-level access control to internal auth fields (#16119) (4ae5577)
  • where querying by a join field with relationship nested to an array (#16101) (0f79eed)
  • trashed documents still show as IDs in relationship responses (#16102) (aa143e6)
  • db-mongodb: virtual fields within blocks (#16107) (77cdb17)
  • db-postgres: stabilize read replicas support (#16083) (46ddf8d)
  • db-postgres: handle blockType filters for versions (#16071) (727d74e)
  • deps: resolve high severity audit vulnerabilities (#16104) (c5a3767)
  • next: respect canAccessAdmin when a custom dashboard view is configured (#16105) (329090c)
  • next: forgot password basePath was not respected (#16084) (3c40241)
  • plugin-multi-tenant: forbidden error when logging in as a user with no tenant and no access to all tenants (#16047) (9c58e7c)
  • richtext-lexical: prevent invalid h0 heading nodes when all heading sizes are disabled (#16090) (185548a)
  • sdk: pass trash to request (#16092) (e0b3e81)
  • storage-gcs: bump @google-cloud/storage (#16046) (5c06266)
  • storage-vercel-blob: properly handle alwaysInsertFields and add comprehensive integration test suite with a vercel blob emulator (#16080) (8530b45)
  • templates: add --no-server-fast-refresh to all dev scripts for Next.js 16.2+ compatibility (#16074) (8045887)
  • ui: prevent data loss in copy-to-locale with drafts (#16073) (43b8de6)
  • ui: tokenInMemory not set after refreshing cookie (#15928) (17266ab)
  • ui: respect admin.dateFormat for list view filters (#16040) (d5fe0ce)

🛠 Refactors

📚 Documentation

  • clarify unique field index behavior and add warnings for array/blocks nesting (#15969) (38c1d4d)
  • document ListViewServerProps/ClientProps and custom list view component patterns (#15970) (eb3b227)
  • adds code examples for how to fully implement textStateFeature (#16053) (80ae745)

🧪 Tests

  • add defaultSort join field property integration tests (#16057) (b2a8917)

📝 Templates

  • fix broken images on Next.js 16 by using relative paths for local media (#16058) (1a0f4d0)
  • bump to Next.js 16.2.1 (#16032) (5c3244f)

⚙️ CI

🏡 Chores

  • claude: update audit-dependencies skill with lockfile strategy and override rules (#16106) (974870a)
  • deps: bump qs-esm from 7.0.2 to 8.0.1 (#16110) (d6862fe)

🤝 Contributors

v3.80.0

20 Mar 18:09
e90fb96

Choose a tag to compare

v3.80.0 (2026-03-20)

🚀 Features

  • add disableUnique property to the slug field for better multi tenant plugin support (#15963) (395e1ed)

🐛 Bug Fixes

  • unpublish updates existing version instead of creating a new one (#15985) (67063ab)
  • use latest draft version data when trashing unpublished documents (#15981) (57a0edc)
  • db-mongodb: fix pagination with collation in transactions (#15990) (5c935aa)
  • db-postgres: near query can give incorrect results (#15907) (843306c)
  • db-sqlite: scheduled publish does not show upcoming events because of wrong nested json querying (#15911) (3fa834a)
  • deps: resolve high severity audit vulnerabilities (#15961) (da212fd)
  • drizzle: pagination applied incorrectly when sorting by a field inside an array field (#15908) (0f67215)
  • drizzle: groups inside localized tabs are not working correctly (#15936) (57bde77)
  • graphql: force nullable for relationships to avoid errors when the related document is related (#15915) (560cabe)
  • plugin-mcp: plugin can break next.js request handler because underlying Hono library modifies the global Request object (#15938) (4cfa495)
  • plugin-multi-tenant: modal container blocks clicks on create-first-user page (#15973) (8157f4c)
  • richtext-lexical: richtext fields don't respect RTL direction for Arabic and other RTL locales (#15964) (944a889)
  • ui: defer live preview iframe rendering (#15999) (9999083)
  • ui: stale data modal shown when onChange starts while save is in-flight (#15960) (dc98f0f)

📚 Documentation

📝 Templates

⚙️ CI

🏡 Chores

  • add docker:clean script and fix docker:start reliability (#16000) (2646018)
  • bump monorepo Next.js version to 16.2.0 (#15992) (a188556)
  • consolidate docker scripts into single docker-compose with profiles (#15974) (f89e736)
  • examples: update astro package.json name (#15118) (4e1c04e)

🤝 Contributors

v3.79.1

16 Mar 14:36
25a0e16

Choose a tag to compare

v3.79.1 (2026-03-16)

🐛 Bug Fixes

  • text field validation rejecting localized object values (#15932) (fac59c8)
  • use Sec-Fetch-Site header for cookie authentication validation (#15751) (ef507a6)
  • improved request origin retrieval (#15919) (f30d34f)
  • generate:types inlines all blocks, add forceInlineBlocks property to use in plugin mcp (#15892) (6a9e367)
  • update broken custom components docs link in config types jsdoc (#15794) (17aa1b5)
  • run sanitizeWhereQuery for join query access result (#15891) (dc049fe)
  • early return out of me access (#15883) (c6054c5)
  • scope orderable join reordering by parent relation (#15842) (17a0d19)
  • stricter input validation (#15868) (e474205)
  • drizzle: avoid ts errors for payload generate:db-schema with circular references (#15895) (66a2efa)
  • drizzle: error when using contains operator on hasMany select fields (#15865) (fba2438)
  • drizzle: correctly apply query limit on polymorphic joins (#15652) (fe36dde)
  • plugin-import-export: add space in zh translation for exportDocu… (#15833) (43d5596)
  • plugin-mcp: bump @modelcontextprotocol/sdk from 1.25.2 to 1.27.1 (#15942) (94d2249)
  • storage-azure: add stream aborts for error handling and connection closure (#15768) (b2a03c9)
  • ui: stale data modal incorrectly shown when user saves their own document (#15933) (a5d9388)
  • ui: copy & pasting block content duplicates array items in editor UI (#15941) (9bcedc8)
  • ui: deleted array item reappears after reorder with autosave (#15906) (752c15a)
  • ui: use consistent empty state styling in relationship table (#15914) (93b90da)
  • ui: clicking filtered Combobox entries fails to trigger selection (#15788) (de3e5ae)
  • ui: document status shows changed after publishing specific locale (#15765) (b95df0b)
  • ui: split only on first colon in toast error messages (#15894) (fd64504)
  • ui: block clipboard paste causes duplicate ID errors in Postgres (#15863) (e7d6331)
  • ui: monomorphic relationship fields don't support multi-select with in/not_in operators (#15886) (f71ef61)
  • ui: equal column widths for block-drawer blocks (#15867) (07f7802)
  • ui: isolate join table column preferences from list view (#15846) (649f117)
  • ui: falling back to UTC timezones in timezone picker (#15841) (70099b7)

⚡ Performance

  • richtext-lexical: 3-15x less main thread blocking via centralized toolbar state (#15832) (2bdf7ce)

📚 Documentation

  • correct type name in editMenuItems client component example (#15904) (03b20d0)
  • adds req to available args and wraps examples with proper String type conversions in nested-docs (#15931) (d2a0740)
  • adds docs for logger config (#15927) (46e43fc)
  • fix links to virtual relationship documentation in both Blocks and Array field documentation (#15888) (fff60c8)
  • broken anchor link in blocks field table (#15887) (36c051a)
  • examples: clarify MongoDB prerequisites in Mongo-backed examples (#15860) (2aa973f)
  • plugin-mcp: updates MCP plugin documentation (#15729) (b97b4e7)

🧪 Tests

  • adjust total test count to exclude todo tests in summary output (#15943) (e46daec)
  • fixes pagination and sorting list-view tests due to hydration timing issues (#15925) (b0f00c4)
  • flaky timeout when clicking Create New button in versions test suite (#15850) (3fb10e1)

🏡 Chores

🤝 Contributors

v3.79.0

04 Mar 19:36
6ae6f10

Choose a tag to compare

v3.79.0 (2026-03-04)

🚀 Features

  • richtext-lexical: separate configuration for lexical block icons (#15632) (f0498f2)
  • richtext-lexical: upgrade lexical from 0.35.0 to 0.41.0 (#15760) (ba3bd74)
  • translations: add i18n translations for modular dashboards (#15004) (cef2838)

Separate Block Icon Configuration (richtext-lexical) — Configure different images for Lexical block icons and block drawer thumbnails independently. Previously, imageURL served both contexts, forcing a compromise between a good 20x20px icon and a good drawer thumbnail. The new images property supports separate icon and thumbnail values with automatic fallback. Fully backwards compatible — imageURL still works but is deprecated. #15632

image
const QuoteBlock: Block = {
  slug: 'quote',
  images: {
    icon: 'https://example.com/icons/quote-20x20.svg',
    thumbnail: { url: 'https://example.com/thumbnails/quote-480x320.jpg', alt: 'Quote block' },
  },
  fields: [...],
}

Lexical Upgrade 0.35.0 → 0.41.0 (richtext-lexical) — Upgrades the Lexical rich text editor dependency from v0.35.0 to v0.41.0. Includes upstream fixes like normalizeMarkdown (facebook/lexical#7812). All Lexical breaking changes are handled internally by Payload — no action required for standard usage. If you installed lexical manually, update it to 0.41.0 (though using the re-exported versions from @payloadcms/richtext-lexical/lexical/* is recommended). #15760

Modular Dashboard Translations (translations) — Adds i18n translation support for the Modular Dashboards feature, covering all dashboard widget buttons and error messages. Previously, dashboard UI elements lacked translation keys, making them inaccessible for non-English users. Also updates the automatic translation script to use GPT-4.1 for improved cost efficiency. #15004

image

🐛 Bug Fixes

  • restoreVersion validation for localized required fields (#15821) (e899182)
  • draft doc validation when duplicating docs (#15816) (f470699)
  • plugin-ecommerce: pass req to Payload API calls in Stripe adapter (#15839) (74799ea)
  • plugin-import-export: automatically inherit locale and limit from URL queries (#15812) (ee083f0)
  • plugin-import-export: fix imports with locales in a different column order than exported (#15808) (410912c)
  • plugin-import-export: fix exports in other non-latin scripts being broken when opened in excel (#15813) (d931894)
  • ui: drag and drop not working for sortable hasMany fields (#15845) (2c7ef3f)
  • ui: prevent false positive stale data modal on autosave-enabled documents (#15817) (6aff717)
  • ui: typo in CodeEditor export statement (#15795) (c5b2a91)

🛠 Refactors

  • rename widget ComponentPath to Component for consistency (#15780) (f7d0d04)

📚 Documentation

🧪 Tests

  • update suites selected by default in runTestsWithSummary (#15789) (07f2f05)

🏡 Chores

  • prevent dev server from dirtying tracked files (#15826) (cb6f426)
  • plugin-search: clean up .DS_Store file and resulting empty images directory (#14506) (f6f73dd)

⚠️ BREAKING CHANGES

  • rename widget ComponentPath to Component for consistency (#15780) (f7d0d04)

    • Renames Widget.ComponentPath to Widget.Component and types it as PayloadComponentinstead ofstring`
    • This aligns dashboard widgets with every other component reference in (collections, globals, fields, admin components) - none of them path in the property name, and all of them are typed as PayloadComponent
    • Enables new typescript plugin to work for widget paths (the plugin uses PayloadComponent contextual type detection - string-typed properties were invisible to it)
  • ui: typo in CodeEditor export statement (#15795) (c5b2a91)

🤝 Contributors

v3.78.0

27 Feb 20:18
05e818e

Choose a tag to compare

v3.78.0 (2026-02-27)

🚀 Features


Feature Details

TypeScript Plugin for Component Paths - New @payloadcms/typescript-plugin validates PayloadComponent import paths directly in your IDE. It checks that referenced files and exports exist, provides autocomplete for file paths and export names, supports go-to-definition on component path strings, and understands all Payload path conventions including absolute paths, relative paths, tsconfig aliases, and package imports. #15779

screenshot.2026-02-26.at.15.55.40.mp4
pnpm add -D @payloadcms/typescript-plugin
{
  "compilerOptions": {
    "plugins": [{ "name": "next" }, { "name": "@payloadcms/typescript-plugin" }]
  }
}

Trash Out of Beta with Granular Delete Access - Trash is now a stable feature. Delete access control can now distinguish between trashing and permanently deleting — allowing you to permit users to soft-delete documents while restricting permanent deletion to admins. When data.deletedAt is being set, the operation is a trash; otherwise it's a permanent delete. #15210

import type { CollectionConfig } from 'payload'

export const Posts: CollectionConfig = {
  slug: 'posts',
  trash: true,
  access: {
    delete: ({ req: { user }, data }) => {
      // Not logged in - no access
      if (!user) {
        return false
      }

      // Admins can do anything (trash or permanently delete)
      if (user.roles?.includes('admin')) {
        return true
      }

      // Regular users: check what operation they're attempting
      // If data.deletedAt is being set, it's a trash operation - allow it
      if (data?.deletedAt) {
        return true
      }

      // Otherwise it's a permanent delete - deny for non-admins
      return false
    },
  },
  fields: [
    // ...
  ],
}

Widget Fields (next, ui) - Dashboard widgets can now declare configurable fields, similar to Blocks. Widget data is editable from a new drawer UI when in dashboard editing mode. Full type generation is included — WidgetInstance<T> is generic with typed data and width, and WidgetServerProps is generic so widget components receive typed widgetData. #15700

Screen.Recording.2026-02-23.at.16.25.40.mov
import { buildConfig } from 'payload'

export default buildConfig({
  admin: {
    dashboard: {
      widgets: [
        {
          slug: 'sales-summary',
          ComponentPath: './components/SalesSummary.tsx#default',
          fields: [
            { name: 'title', type: 'text' },
            {
              name: 'timeframe',
              type: 'select',
              options: ['daily', 'weekly', 'monthly', 'yearly'],
            },
            { name: 'showTrend', type: 'checkbox' },
          ],
          minWidth: 'small',
          maxWidth: 'medium',
        },
      ],
    },
  },
})
import type { WidgetServerProps } from 'payload'

import type { SalesSummaryWidget } from '../payload-types'

export default async function SalesSummaryWidgetComponent({
  widgetData,
}: WidgetServerProps<SalesSummaryWidget>) {
  const title = widgetData?.title ?? 'Sales Summary'
  const timeframe = widgetData?.timeframe ?? 'monthly'

  return (
    <div className="card">
      <h3>
        {title} ({timeframe})
      </h3>
    </div>
  )
}

MCP Plugin Out of Beta (plugin-mcp) - @payloadcms/plugin-mcp is now stable and ready for production use. #15711

Virtual Field Filtering in MCP (plugin-mcp) - Virtual fields (virtual: true) are now automatically stripped from MCP tool input schemas and filtered from parsed data before create, update, and updateGlobal operations. This prevents non-stored fields from appearing as accepted MCP parameters. #15680

Markdown Transformer for Upload Nodes (richtext-lexical) - Upload nodes are now properly converted when using convertLexicalToMarkdown. Previously, upload nodes were silently dropped during markdown conversion. Now populated image uploads output ![alt text](/uploads/image.jpg), non-image uploads output link syntax, and non-populated uploads output a reference placeholder so data is never lost. #15630

Dashed Button Style (ui) - Adds a new dashed button style variant. Also replaces box-shadow with border on all buttons and fixes icon-only button padding. #15728

Button styles overview

Editable Query Presets from Form View (ui) - Query presets can now be created and edited directly from the document form view using a full WhereBuilder, column picker, and groupBy selector — no longer requiring the list view to build queries first. #15657

Screen.Recording.2026-02-17.at.18.15.34.mov

🐛 Bug Fixes

  • getFieldsToSign crashes when user missing group/tab fields (#15775) (9f0c101)
  • improve mobile touch support for dnd (#15771) (418bb92)
  • prevent silent data overwrites on concurrent edits (#15749) (7a3f43f)
  • preserve block metadata in mergeLocalizedData and filterDataToSelectedLocales (#15715) (6557292)
  • return 400 for malformed JSON request bodies (#15706) (4861fa1)
  • globals not updating updatedAt when saving drafts (#15764) (df17cb1)
  • return early if pasteURL is not defined (#15748) (23d52a0)
  • prevent req.file leak between sequential duplicate() calls on upload collections (#15620) (2baea2e)
  • sanitize filenames in storage adapters (#15746) (45bd2f1)
  • throw error for unknown query operators (#15739) (08226db)
  • preserve locale data in unnamed groups with localizeStatus (#15658) (38b8c68)
  • next: conditionally query snapshot field based on localization (#15693) (d5706ee)
  • plugin-import-export: update docs on jobs and basic usage as well as visibility (#15695) (a40210c)
  • plugin-mcp: use inline block schemas in JSON output (#15675) (a66e844)
  • plugin-multi-tenant: hasMany tenant fields double-wrap arrays in filterOptions (#15709) (aaddeac)
  • plugin-multi-tenant: return false instead of query when no tenants (#15679) ([f5a5bd8](https://github....
Read more

v3.77.0

18 Feb 19:39
71be0ca

Choose a tag to compare

v3.77.0 (2026-02-18)

🚀 Features

  • pass local API depth through to req.query.depth for consistency (#15023) (9a38469)
  • db-*: add customID arg to db.create (#15653) (0935824)
  • plugin-mcp: migrate from @vercel/mcp-adapter to mcp-handler (#15661) (24025fd)

Feature Details

Local API Depth Consistency - The depth option passed to Local API calls like payload.find() is now automatically set on req.query.depth. Previously, hooks relying on req.query.depth would behave differently between Local API and REST/GraphQL calls unless you manually passed req: { query: { depth: x } } in addition to depth: x. This change ensures consistent behavior across all API methods. #15023

Custom ID Support in db.create (db-*) - New customID argument on payload.db.create allows creating documents with a specific ID without requiring a custom ID field in your collection schema. #15653

payload.db.create({ collection: 'posts', customID: 'ce98d6c4-c3ab-45de-9dfc-bf33d94cc941', data: { } })

MCP Plugin Migration (plugin-mcp) - Migrates from the deprecated @vercel/mcp-adapter to mcp-handler and bumps @modelcontextprotocol/sdk to 1.25.2 addressing a security vulnerability. Exposes new handler options: disableSse, onEvent, and redisUrl. #15661

import { mcpPlugin } from '@payloadcms/plugin-mcp'

export default buildConfig({
  plugins: [
    mcpPlugin({
      // Optional: Enable SSE transport (disabled by default)
      disableSse: false,
      // Optional: Redis URL for SSE session management (defaults to REDIS_URL env)
      redisUrl: 'redis://localhost:6379',
      // Optional: Track MCP events for analytics/debugging
      onEvent: (event) => {
        console.log('MCP event:', event)
      },
    }),
  ],
})

🐛 Bug Fixes

  • hasMany text fields cannot be filtered with contains operator (#15671) (4513a05)
  • use consistent empty state styling between list and folder views (#15555) (8953b37)
  • populate previousValue correctly in afterChange hooks for nested lexical fields (#15623) (1cc3bb9)
  • add i18n support for dashboard edit mode buttons (#15564) (818e31d)
  • next: handle undefined fieldTab in version diff tabs (#15590) (bbacab8)
  • plugin-cloud-storage: ensure file data persists across operations (#15570) (6af3673)
  • plugin-cloud-storage: generateFileURL only ran when disablePayloadAccessControl was true (#15667) (6c5611c)
  • plugin-import-export: remove deprecated import (#15666) (733b1df)
  • plugin-import-export: export and import issues when using custom IDs (#15518) (7e2a3ab)
  • plugin-import-export: columns being duplicated when using toCSV hook (#15597) (28e07dc)
  • plugin-mcp: resolve union type fields failing in update tool (#15660) (9ae89dd)
  • plugin-multi-tenant: improve translation for "Tenant" (use "Mandant" instead of "Mieter") (#15537) (4d4033b)
  • plugin-multi-tenant: tenant selector not appearing after login (#15617) (dd09f67)
  • storage-r2: build error due to types issue in R2 Bucket type (#15670) (7d1e233)
  • ui: fix broken polymorphic join edit drawer (#15621) (d450e99)

📚 Documentation

🧪 Tests

  • trash e2e tests check URL before navigation completes (#15599) (7fe5a8c)

🏡 Chores

  • add md and mdx language block linting (#15309) (5415516)
  • bump playwright to fix vscode run test indicators (#15626) (f74d288)
  • only add publishAllLocales to publish when localizeStatus is enabled (#15610) (d57bc22)

🤝 Contributors

v3.76.1

11 Feb 18:34
3a486c5

Choose a tag to compare

v3.76.1 (2026-02-11)

🐛 Bug Fixes

  • use optional chaining for adminThumbnail size lookup to prevent crash (#15586) (6937eec)
  • non-image files should not recieve 0 bytes with useTempFiles (#15538) (a313627)
  • add CSP headers to SVG uploads to prevent XSS (#15506) (8283c25)
  • richtext-lexical: link tooltip overflows outside viewport with long URLs (#15584) (af6b1a1)
  • ui: prevent Tabs field crash when stored tabIndex exceeds tab count (#15588) (a9e296e)
  • ui: copy to locale function swallowing errors (#15562) (8ce62d8)
  • ui: ensure unpublish button only shows when drafts are enabled (#15459) (69dc5e6)

⚙️ CI