WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Releases: payloadcms/payload

v3.67.0

05 Dec 20:34
e818a01

Choose a tag to compare

v3.67.0 (2025-12-05)

🚀 Features

  • add groupBy support to query presets (#14808) (2b7aa7a)
  • plugin-ecommerce: add ability to enable guest carts with reworked access config (#14565) (90c92f4)

GroupBy Support for Query Presets - Query presets now save and restore groupBy state when switching between presets. Previously, groupBy settings would persist across preset switches and weren't saved as part of the preset configuration. #14808

Preset creation with group-by added

Guest Carts (plugin-ecommerce) - Enable guest users to create and manage carts without authentication. Carts created by guests are secured with a generated secret stored in local storage. Configure with allowGuestCarts (enabled by default). Also adds isLoading status to all hooks for conditional UI state.
#14565

// Before
ecommercePlugin({
  access: {
    adminOnly,
    adminOnlyFieldAccess,
    adminOrCustomerOwner,
    adminOrPublishedStatus,
    customerOnlyFieldAccess,
  }
})

// After
ecommercePlugin({
  access: {
    adminOnlyFieldAccess,
    adminOrPublishedStatus,
    customerOnlyFieldAccess,
    isAdmin,
    isDocumentOwner,
  }
})

🐛 Bug Fixes

  • add missing beforeInput and afterInput properties to UploadAdmin type (#14775) (22a0255)
  • add missing afterOperation and beforeOperation hook calls (#14778) (e9cd2a5)
  • sanitized versions type was incorrect (#14810) (51c951f)
  • plugin-multi-tenant: moves getGlobalViewRedirect from utilities to rsc exports (#14817) (1340818)
  • ui: autosave not queued while background process is in flight (#14805) (14f042f)
  • ui: ensure block error css only gets applied to the affected block (#14826) (7520140)
  • ui: missing translation support in SelectMany component (#14819) (8fa91a5)

⚡ Performance

⚙️ CI

  • clean up bug report template for auto-labeling (ebee8e1)

🏡 Chores

  • claude: add coding patterns and best practices section (#14829) (c5d8e68)
  • deps: bump @types/react and @types/react-dom to 19.2.1 (#14815) (d56796b)
  • deps: bump next to 15.4.8 in root and test dirs (#14811) (1c3417d)

⚠️ BREAKING CHANGES

  • plugin-ecommerce: add ability to enable guest carts with reworked access config (#14565) (90c92f4)

This PR introduce a breaking change into the plugin as it was necessary
in order to provide more secure guest carts.

🤝 Contributors

v3.66.0

03 Dec 21:20
7cc28c4

Choose a tag to compare

v3.66.0 (2025-12-03)

⚠️ Security Issue

A critical-severity vulnerability in React Server Components (CVE-2025-55182) affects React 19 and frameworks that use it, including Next.js (CVE-2025-66478).

You are strongly encouraged to immediately upgrade your own apps to the nearest patched versions of React and Next.js.

While this is not a Payload vulnerability, it may affect any Payload project running on the affected versions of React or Next.js. Payload does not install any of these dependencies directly, it simply enforces their versions through its peer dependencies, which will only warn of the version incompatibilities.

You will need to upgrade React and Next.js yourself in your own apps to the patched versions listed below in order to receive these updates.

Quick steps:

If using pnpm as your package manager, here's a one-liner:

To do this manually:

  1. In your package.json:
    • Bump react to 19.2.1
    • Bump next to 15.4.8
  2. Reinstall node modules, e.g. pnpm i
  3. Redeploy your app

Here's a full breakdown of the vulnerable packages and their patched releases:

Vulnerable package Patched release
React 19.0, 19.1, 19.2 19.0.1, 19.1.2, and 19.2.1
Next.js 14.3.0-canary, 15.x, and 16.x (App Router) 14.3.0-canary.88, 15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7, 16.0.7

See #14807 for more details.

🚀 Features

  • support custom slugify functions (#14117) (59a1607)
  • accessibility testing and improvements (#14454) (42cbd70)
  • support external JSON schema file references in type generation (#14749) (cb3a078)
  • cpa: assume adapter for with-cloudflare-d1 template (#14799) (4f03016)
  • richtext-lexical: add align support to upload nodes (#14720) (a21c47b)

Feature Details

Custom Slugify Functions - Override the default slug field behavior with your own slugify function. Useful for special character encoding, additional language support, or custom slug formatting. Also deprecates fieldToUse in favor of useAsSlug for consistency with useAsTitle. #14117

import type { CollectionConfig } from 'payload'
import { slugField } from 'payload'
import slugify from 'slugify';

export const MyCollection: CollectionConfig = {
  // ...
  fields: [
    // ...
    slugField({
      slugify: ({ valueToSlugify }) => slugify(valueToSlugify, {
        // ...additional `slugify` options here
      })
    })
  ]
}

Accessibility Testing and Improvements - Adds automated accessibility testing infrastructure including axe a11y scans, focus indicator checks, and horizontal scroll overflow detection. Covers all fields, major views, components, plugins, and Lexical editor. See the a11y report discussion for tracked issues. #14454

External JSON Schema References in Type Generation - Enables $ref pointers to external .json schema files in typescriptSchema field config. External references are resolved relative to process.cwd(). #14749

// payload.config.ts
{
  typescript: {
    schema: [
      ({ jsonSchema }) => {
        jsonSchema.definitions.MyType = {
          $ref: './schemas/my-type.json'
        }
        return jsonSchema
      },
    ]
  }
}

Auto-detect D1 Adapter (cpa) - The with-cloudflare-d1 template now automatically assumes the D1 database adapter, eliminating the database selection prompt during project creation. #14799

Upload Node Alignment (richtext-lexical) - Adds alignment support to upload nodes in the Lexical editor. Upload/media blocks can now be aligned left, center, or right using the FORMAT_ELEMENT_COMMAND. #14720

Upload alignment support

🐛 Bug Fixes

  • remove "all" from JSDoc comment on supported http methods in endpoints (#14777) (8c8def9)
  • should exclude svg files from file buffer mime validation (#14751) (015b363)
  • deps: bump minimum react and next versions (#14807) (2dfe464)
  • plugin-import-export: incorrect user type in Export causing runtime type mismatch (#14790) (61f5aee)
  • plugin-multi-tenant: tenant modal not appearing when autosave is off (#14806) (b96e928)
  • plugin-multi-tenant: auto assign tenant when autosave is enabled (#14745) (b0674fa)
  • richtext-lexical: copying and pasting a single block in Lexical results in an error due to duplicate ID (#14738) (cd9addf)
  • richtext-lexical: export serverInlineBlock modules (#14739) (becceb7)
  • translations: translate slug field actions (#14784) (5542e56)
  • ui: prevent NaN page parameter in polymorphic relationship pagination (#14795) (bbdfdb8)
  • ui: reduce spacing between checkbox and first column when few columns shown (#14776) (6ae1bc8)

📚 Documentation

🧪 Tests

📝 Templates

  • update with-cloudflare-d1 to the latest OpenNext and wrangler (#14509) (5150388)

⚙️ CI

🏡 Chores

⚠️ BREAKING CHANGES

🤝 Contributors

v3.65.0

25 Nov 18:47
fde824b

Choose a tag to compare

v3.65.0 (2025-11-25)

🚀 Features

  • add augmentable interfaces for collection and global custom properties (#14729) (850c252)
  • allow to specify payload instance cache key in handleEndpoints (#14675) (efa2fd2)
  • db-mongodb: add afterCreateConnection and afterOpenConnection hooks (#14649) (af6ba86)
  • plugin-mcp: add localization support to MCP resource operations (#14334) (a3f490b)
  • plugin-mcp: adds a PayloadRequest to custom tool, prompt, and resource handlers (#14644) (0d14b06)
  • ui: extract block selector from blocks drawer (#14697) (b9b11f0)

Type-Safe Custom Properties - Add augmentable interfaces for collection and global custom properties: CollectionCustom, CollectionAdminCustom, GlobalCustom, and GlobalAdminCustom. Enables type-safe plugin configuration at the collection/global level with full autocomplete support, matching the existing FieldCustom pattern. #14729

// Augment interfaces in your plugin or project
declare module 'payload' {
  export interface CollectionAdminCustom {
    disabledFields?: string[]
  }

  export interface CollectionCustom {
    myPluginConfig?: {
      enabled: boolean
      settings: Record<string, any>
    }
  }
}

// Now get full type safety in collections
export const Posts: CollectionConfig = {
  slug: 'posts',
  admin: {
    custom: {
      disabledFields: ['status'] // ✅ Type-safe!
    }
  },
  custom: {
    myPluginConfig: {
      enabled: true,
      settings: {}
    }
  }
}

Payload Instance Cache Key - Specify payloadInstanceCacheKey in handleEndpoints and createPayloadRequest to control which cached Payload instance is used for custom endpoints. Useful for multi-tenant scenarios or when managing multiple Payload instances. #14675

MongoDB Connection Lifecycle Hooks (db-mongodb) - Add afterCreateConnection and afterOpenConnection hooks to the MongoDB adapter for performing setup logic after connection/pool initialization. Enables use cases like connection pooling in serverless environments. #14649

export const databaseAdapter = mongooseAdapter({
  // ...
  afterOpenConnection: async (adapter) => {
    const client = adapter.connection.getClient()
    attachDatabasePool(client);
  },
})

MCP Localization Support (plugin-mcp) - Add full localization support to MCP resource operations (create, update, find, delete). All MCP tools now accept locale and fallbackLocale parameters, bringing feature parity with Payload's REST API for multilingual content management. #14334

// Create content in English
{ "name": "createPosts", "arguments": { "title": "Hello", "locale": "en" }}

// Add Spanish translation
{ "name": "updatePosts", "arguments": { "id": "123", "title": "Hola", "locale": "es" }}

// Retrieve all translations
{ "name": "findPosts", "arguments": { "id": "123", "locale": "all" }}

PayloadRequest in MCP Handlers (plugin-mcp) - Custom tool, prompt, and resource handlers now receive a PayloadRequest object, enabling access to the Payload instance and consistent access control patterns without additional lookups. #14644

// Previously
handler: async (args: Record<string, unknown>) => {}

// Now with req parameter
handler: async (args: Record<string, unknown>, req: PayloadRequest, _extra) => {
  // Access payload instance, user, locale, etc.
  const { payload, user, locale } = req
}

Reusable Block Selector Component (ui) - Extract BlockSelector component from BlocksDrawer and export for external use. Includes new onSelect callback for custom side effects when blocks are selected. #14697

🐛 Bug Fixes

  • trigger login hooks after reset password (#14711) (32560e9)
  • ensure restoreAsDraft only updates the published doc when draft is false (#14658) (3f3f5db)
  • remove init of transaction for global doc access (#14693) (c455f58)
  • count versions should allow querying on localized fields (#14695) (e1168a0)
  • prevent upload mimeType error when useTempFiles is true (#14689) (fe8a3e8)
  • autoRefresh not working due to stale closure and missing in client config (#14612) (8a3c6dc)
  • type TypeWithVersion missing latest property (#14676) (9b6e1a3)
  • graphql version error in production (#14622) (cd5b344)
  • corrects outgoing localized data from afterRead (#14603) (87137fe)
  • relationships should not fallback if fallbackLocale is false (#14641) (9f55254)
  • hide turbopack warnings (#14640) (03f19bc)
  • logout-inactivity route gets stuck on loading indicator when inactivity and isLoggedIn are true (#14596) (7a31c02)
  • tighten up error visibility handling (#14606) (c74a40f)
  • claude: properly structure claude plugin (#14432) (3198bbe)
  • db-*: do not exit process on error during connect (#14647) (ab03163)
  • db-mongodb,drizzle: prevent race condition in transaction session cleanup (#14651) (a7cf30d)
  • drizzle: postgres 18 support (#14700) (294ebf5)
  • next: remove turbopack build support to fix bundle size regression (#14696) (c484a05)
  • next: prevent transaction race condition in renderDocument parallel operations (#14652) (802a21a)
  • plugin-multi-tenant: fix infinite sync tenant network calls (#14604) (8901c7b)
  • richtext-lexical: block names were not loaded (#14698) (c7a87c0)
  • ui: ensures modal closes on route change (#14718) (a044a08)
  • ui: query preset crash with empty filters in postgres/sqlite (#14722) (42a4384)
  • ui: app header overflow on mobile (#14704) (91d3e04)
  • ui: shows minRowsProp instead of minRows (#14681) (e40a4b7)
  • ui: publish label regression from 14690 (#14692) (ba5834b)
  • ui: publish button shows locale-specific text without localized fields (#14690) (caf68e4)
  • ui: equals filter shows no results when value is cleared (#14673) ([220a18f](https://github.com/payloadcms/payload/comm...
Read more

v3.64.0

13 Nov 19:35
2394fe6

Choose a tag to compare

v3.64.0 (2025-11-13)

🚀 Features

  • add support for UTC timezone in date fields (#14586) (8b34e40)
  • next: turbopack build support, fix incorrect handling of external packages (#14475) (3a975d7)
  • plugin-mcp: adds MCP context to req.payloadAPI (#14595) (860bdf2)
  • plugin-mcp: adds custom auth config (#14538) (73a18dc)
  • plugin-redirects: support translations (#14548) (ad8f0b2)

UTC Timezone Support - Add support for 'UTC' as a timezone value in date fields. Previously unsupported due to validation against Intl API runtime values. Also fixes issue where having only one timezone would make it selected by default. #14586

import { buildConfig } from 'payload'

const config = buildConfig({
  admin: {
    timezones: {
      supportedTimezones: [
        {
          label: 'UTC',
          value: 'UTC',
        },
      ],
      defaultTimezone: 'UTC',
    },
  },
})

Turbopack Build Support - Full support for Turbopack builds (now default in Next.js 16). Properly externalizes database adapter entry points to prevent production failures. Resolves issues with direct dependency externalization causing runtime errors. #14475

MCP Context Detection - Detect when Payload API calls originate from MCP context using req.payloadAPI === 'MCP'. Enables conditional logic in hooks based on MCP usage. #14595

export const Posts: CollectionConfig = {
  slug: 'posts',
  hooks: {
    beforeRead: [
      ({ doc, req }) => {
        if (req.payloadAPI === 'MCP') {
          doc.title = `${doc.title} (MCP Hook Override)`
        }
        return doc
      },
    ],
  },
}

Custom Auth Configuration - Override default API key authentication with custom authorization logic using overrideAuth. Provides granular control over MCP access permissions. #14538

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

plugins: [
  mcpPlugin({
    overrideAuth: (req) => {
      return {
        posts: { find: true },
        products: { find: true, update: true },
      } as MCPAccessSettings
    },
  })
]

Redirect Plugin Translation Support - Enable translations for plugin fields, eliminating need for verbose field overrides configuration. Configure field labels in multiple languages directly through i18n config. #14548

export default buildConfig({
  i18n: {
    translations: {
      en: {
        'plugin-redirects': {
          fromUrl: 'Source URL (Custom)',
        },
      },
      de: {
        'plugin-redirects': {
          fromUrl: 'Quell-URL',
          internalLink: 'Interner Link',
        },
      },
    },
  },
  plugins: [redirectsPlugin({ collections: ['pages'] })],
})

🐛 Bug Fixes

  • previous value undefined for nested fields in afterChange (#14582) (d60ea6e)
  • default values inconsistent between Local and REST APIs (#14556) (8f7ef35)
  • findGlobalVersionByID id type (#14534) (99ed0e5)
  • localized block fields (#14587) (2295c89)
  • add secondary PDF mimeType validation and tests (#14529) (ce479ab)
  • unlock access not being correctly denied when using a where query (#14585) (f63e34e)
  • error when calling jobs.handleSchedules when there are no schedules defined (#14519) (072cb97)
  • changing the language of the admin panel does not work for "radio" and "select" fields. (#14569) (bb520d6)
  • inject custom translations into supportedLanguages in sanitization (#14549) (d7f1ea2)
  • db-mongodb: localization transforms on nested localized fields (#14600) (6070d8d)
  • db-mongodb: findVersions/findGlobalVersions not respecting limit of 0 (#14573) (43dcf84)
  • graphql: avoid errors with sort as empty string (#14594) (fad476d)
  • next: turbopack error when using db-d1-sqlite package (#14558) (bd6decf)
  • next, ui: show status "changed" in List View (#14555) (565680d)
  • plugin-form-builder: expose formSubmissionID as a variable to be used in emails (#14429) (ad74386)
  • plugin-mcp: correctly uses local access controls (#14457) (fc2becf)
  • richtext-lexical: urls being wrongly encoded by incomplete URL validation (#14557) (2cb0c59)
  • storage-r2: respect data.prefix in handleUpload path construction (#14485) (454d0d3)
  • ui: error on inserting new documents on uploads with hasMany (#14567) (fd44d2b)
  • ui: save button becomes disabled after failed save with draft validation (#14584) (6fda71a)
  • ui: invalid req.locale shows incorrect data (#14537) (f29a07f)

⚡ Performance

  • ui: don't return full documents on bulk UI operations (#14145) (4430739)

🛠 Refactors

📚 Documentation

🧪 Tests

  • move draft validation tests from form-state to field error states test suite (#14599) (e1f07ff)
  • run cpa against create-next-app latest and canary (#14583) (cca97c6)
  • 21x faster versions int suite (#14510) (844f99f)

📝 Templates

⚙️ CI

  • fix ERR_PNPM_ADDING_TO_ROOT in create-payload-app int (#14581) (6789939)

🏡 Chores

  • add .worktrees to .gitignore (87f2bd9)
  • fix serverExternalPackages errors in monorepo (#14535) (e76da3f)

🤝 Contributors

v3.63.0

07 Nov 15:16
5bf3bd4

Choose a tag to compare

v3.63.0 (2025-11-07)

🚀 Features

Polymorphic Uploads

Upload fields can now reference multiple upload collections, similar to polymorphic relationships. This enables more flexible media management where a single field can accept different types of files from various collections. Works seamlessly with bulk upload and hasMany options. #14363

import type { CollectionConfig } from 'payload'

export const ExampleCollection: CollectionConfig = {
  slug: 'example-collection',
  fields: [
    {
      name: 'media',
      type: 'upload',
      relationTo: ['images', 'documents', 'videos'], // references multiple upload collections
    },
  ],
}

Can also be combined with hasMany:

import type { CollectionConfig } from 'payload'

export const ExampleCollection: CollectionConfig = {
  slug: 'example-collection',
  fields: [
    {
      name: 'media',
      type: 'upload',
      relationTo: ['images', 'documents', 'videos'], // references multiple upload collections
      hasMany: true, // allows multiple uploads
    },
  ],
}

🐛 Bug Fixes

  • use TSiblingData for previousSiblingDoc in FieldHook (#14503) (339a0c3)
  • support generic types for kv.get (#14494) (f6194c6)
  • group-by sticky pagination not rendering for virtual relationship fields (#14470) (648021c)
  • ensure importMap is reliably generated during HMR (fixes Next.js 16 issue) (#14474) (61a7095)
  • hmr not working in next.js 16 (#14462) (0231a8d)
  • disable lockedDocuments if the kv adapter uses a collection (#14453) (827c9a1)
  • drizzle: postgesql where in jsonb (#13742) (207295b)
  • graphql: sort by multiple fields (#14486) (b925d34)
  • next: withPayload wrapper next.js 16 support (#14473) (c0de75e)
  • next: version._status field queried/returned for entities without drafts (#14423) (a22dff3)
  • plugin-cloud-storage: file sizes use correct mime type (#11633) (2410296)
  • richtext-lexical: prevent unnecessary requests for inline blocks (#14522) (69408f0)
  • richtext-lexical: bulk upload drawer rendered at the wrong depth if already in a drawer (#14472) (4fd8d03)
  • ui: virtual fields disappearing from filter/groupBy dropdowns with access control (#14514) (a3c0e84)
  • ui: safely access fieldPermissions (#14458) (2393721)
  • ui: simplify UI orderable collections table by allowing only ascending order (#14433) (eba6cfc)

⚡ Performance

  • ui: avoid unnecessary remounting of DraggableSortable (#14463) (91e64b3)

🛠 Refactors

  • use formatNames utility for interface name generation (#14481) (39bead7)

📚 Documentation

🧪 Tests

📝 Templates

  • remove payload cloud template, remove cloud plugin from templates (#14479) (76ba2df)
  • remove outdated cloning and payload cloud information (#14484) (d4d9622)

🔨 Build

⚙️ CI

  • speed up workflow reruns, remove run_number from build cache key (#14448) (f67d031)
  • add kv and plugin-mcp to valid PR scopes (be0943a)

🏡 Chores

🤝 Contributors

v3.62.1

03 Nov 16:27
14537f7

Choose a tag to compare

v3.62.1 (2025-11-03)

🐛 Bug Fixes

The KV implementation was requiring all postgres users to have to create a new migration. The following fix prevents that.

  • disable lockedDocuments if the kv adapter uses a collection (#14453) (6930aaf)

v3.62.0

30 Oct 18:09
d401424

Choose a tag to compare

v3.62.0 (2025-10-30)

🚀 Features

Jobs Access Control

Adds role-based access control for job queue and cancel operations, allowing you to restrict who can manage background jobs in your application. Both operations now support overrideAccess parameter and respect custom access control functions defined in your jobs configuration. #14404

// Configure access control
jobs: {
  access: {
    queue: ({ req }) => req.user?.roles?.includes('admin'),
    cancel: ({ req }) => req.user?.roles?.includes('admin'),
  }
}

// Use in Local API
await payload.jobs.cancel({
  where: { workflowSlug: { equals: 'sync' } },
  overrideAccess: false,
  req,
})

Per-Field Timezone Configuration

Date fields can now have individual timezone settings, allowing different date fields to support their own list of supported timezones with custom default values. This enables more flexible date handling across your application. #14410

{
  name: 'date',
  type: 'date',
  timezone: {
    defaultTimezone: 'America/New_York',
    supportedTimezones: [
      { label: 'New York', value: 'America/New_York' },
      { label: 'Los Angeles', value: 'America/Los_Angeles' },
      { label: 'London', value: 'Europe/London' },
    ],
  },
}

You can also enforce a specific timezone by specifying just one with a default value:

{
  name: 'date',
  type: 'date',
  timezone: {
    defaultTimezone: 'Europe/London',
    supportedTimezones: [
      { label: 'London', value: 'Europe/London' },
    ],
  },
}

KV Storage Adapters

Introduces a new key-value storage system with multiple adapter options (Database, In-Memory, Redis) for enhanced data persistence and performance. This provides the foundation for the upcoming Realtime API and other features requiring fast key-value access. #9913

Access the KV store via payload.kv with the following interface:

interface KVAdapter {
  /**
   * Clears all entries in the store.
   * @returns A promise that resolves once the store is cleared.
   */
  clear(): Promise<void>

  /**
   * Deletes a value from the store by its key.
   * @param key - The key to delete.
   * @returns A promise that resolves once the key is deleted.
   */
  delete(key: string): Promise<void>

  /**
   * Retrieves a value from the store by its key.
   * @param key - The key to look up.
   * @returns A promise that resolves to the value, or `null` if not found.
   */
  get(key: string): Promise<KVStoreValue | null>

  /**
   * Checks if a key exists in the store.
   * @param key - The key to check.
   * @returns A promise that resolves to `true` if the key exists, otherwise `false`.
   */
  has(key: string): Promise<boolean>

  /**
   * Retrieves all the keys in the store.
   * @returns A promise that resolves to an array of keys.
   */
  keys(): Promise<string[]>

  /**
   * Sets a value in the store with the given key.
   * @param key - The key to associate with the value.
   * @param value - The value to store.
   * @returns A promise that resolves once the value is stored.
   */
  set(key: string, value: KVStoreValue): Promise<void>
}

Configure the adapter using the kv property:

buildConfig({
  kv: adapter()
})

Database KV adapter (default) - Uses your existing database with a hidden payload-kv collection:

import { databaseKVAdapter } from 'payload'

buildConfig({
  kv: databaseKVAdapter({
    kvCollectionOverrides: {
      slug: 'custom-kv',
      ...(process.env.DEBUG === 'true' && {
        admin: { hidden: false },
        access: {},
      }),
    },
  }),
})

In Memory KV adapter - Fast memory-based storage for development:

import { inMemoryKVAdapter } from 'payload'

buildConfig({
  kv: inMemoryKVAdapter(),
})

Redis KV Adapter - Production-ready Redis integration:

pnpm add @payloadcms/kv-redis
import { redisKVAdapter } from '@payloadcms/kv-redis'

buildConfig({
  kv: redisKVAdapter({
    keyPrefix: "custom-prefix:", // defaults to 'payload-kv:'
    redisURL: "redis://127.0.0.1:6379" // defaults to process.env.REDIS_URL
  }),
})

Configurable Toast Position

Toast notifications can now be positioned anywhere on the screen (top-left, top-center, top-right, bottom-left, bottom-center, bottom-right), giving you control over where important messages appear to your users. This is particularly useful for applications with large screens or specific UI layouts. #14405

The position configuration is a direct pass-through of the Sonner library's position options, with 'bottom-right' remaining the default.

Feature PRs

🐛 Bug Fixes

  • globals with versions return _status field when access denied (#14406) (b766ae6)
  • custom dashboard component causes runtime error on create-first-user and account views (#14393) (d5f4e72)
  • claude: remove invalid frontmatter fields (#14411) (118d005)
  • db-*: findMigrationDir in projects without src folder (#14381) (059185f)
  • db-mongodb: migration fails for cosmosDB (#14401) (10a640c)
  • db-mongodb: type error with prodMigrations (#14394) (8e5e23a)
  • db-mongodb: duplicate ids in sanitizeQueryValue (#11905) (36bb188)
  • db-postgres: hasMany relationship/number/text fields inside blocks are incorrectly returned when using select (#14399) (850cc38)
  • drizzle: number fields in generated schema with defaultValue (#14365) (8996b35)
  • plugin-multi-tenant: remove unused syncTenants from useEffect deps (#14362) (906a3dc)
  • richtext-lexical: do not run json.parse if value is undefined or null (#14385) (09a6140)
  • richtext-lexical: prevent TS CodeBlocks from sharing Monaco model (useId) (#14351) (5caebd1)
  • storage-*: update the client cache to use a map instead with cache keys per bucket config (#14267) (38f2e1f)
  • ui: where builder crashing with invalid queries (#14342) (6c83046)

🛠 Refactors

  • deprecate job queue depth property (#14402) (1341f69)
  • ui: simplify ConfigProvider, improve useControllableState types and defaultValue fallback (#14409) (255320e)

⚙️ CI

  • add claude as valid scope (560f2f3)

🤝 Contributors

v3.61.1

24 Oct 21:25
bc6228c

Choose a tag to compare

v3.61.1 (2025-10-24)

🐛 Bug Fixes

  • ui: ask before closing doc drawer with edits (#14324) (c1d017a)
  • filteredLocales in the client config are stale (#14326) (5a37909)
  • db-*: querying joins with $exists on mongodb and improve performance when querying multiple times on postgres (#14315) (1f166ba)
  • db-postgres: regression in migrations in the _rels table (#14341) (a2b1c9b)
  • plugin-search: add locale to key in syncedDocsSet (#14289) (c29e1f0)
  • ui: account for array values in transformWhereToNaturalLanguage (#14339) (f2cabe7)
  • ui: preview button not responding to conditional URL (#14277) (ad0e7b2)
  • ui: use depth: 0 for publish specific locale request (#14313) (b68715e)

📚 Documentation

🤝 Contributors

v3.61.0

23 Oct 15:46
32479f2

Choose a tag to compare

v3.61.0 (2025-10-23)

🚀 Features

  • @payloadcms/plugin-mcp Released (BETA) - New plugin that enables Payload to function as an MCP server, allowing AI models to interact with your collections through a standardized protocol. The plugin provides built-in tools for CRUD operations on collections and supports custom tools. #13674

🐛 Bug Fixes

  • user updatedAt modified during session operations (#14269) (a1671ec)
  • document header text clipping (#14291) (db973e9)
  • typescript requires fields when draft: true despite passing draft: true (#14271) (1016cd0)
  • blocks access control not respecting update access whether on collection or on a per field basis (#14226) (88cb687)
  • allow slugField to accept localized argument and fixed slug generation with custom field names (#14234) (2ced43d)
  • db-postgres: limit index and foreign key names length (#14236) (a63b4d9)
  • drizzle: folders with trash enabled don't display documents in polymorphic joins (#14223) (6d3aaaf)
  • plugin-form-builder: display full textarea content in form submissions (#14161) (24dad01)
  • plugin-multi-tenant: block references issue (#14320) (4f8b7d2)
  • plugin-search: exclude skipped drafts in reindex handler (#14224) (0dc782c)
  • richtext-lexical: ensure block node form displays up-to-date value when editor remounts (#14295) (f8e6b65)
  • richtext-lexical: node replacements ignored for block, inline block, upload, unknown and relationship nodes (#14249) (1561853)
  • richtext-lexical, ui: ui errors with Slash Menu in Lexical and SearchBar component in RTL (#14231) (fed3bba)
  • ui: document locked modal blocks interaction after clicking Go Back (#14287) (5782a41)
  • ui: change password button being hidden and unlock button being shown incorrectly on account page (#14220) (bcb4d8e)

⚡ Performance

  • richtext-lexical: decrease size of field schema, minor perf optimizations (#14248) (e25ce1c)
  • richtext-lexical: do not return i18n from editor adapter (#14228) (54224c3)

🛠 Refactors

  • richtext-lexical: ensure classNames of all nodes can be customized (#14294) (e1ef1d2)

📚 Documentation

  • improve slate to lexical migration docs (#14309) (6838c56)
  • db indexes - code example missing const (#14171) (3b37f4a)
  • add explanation about re-renders in useFormFields (#14288) (8cdb5dc)
  • add jsdocs to RichText adapter (#14246) (8b0ac01)
  • clarify admin.timezones list configuration with example (#14238) (de5f3db)
  • fix link to slug-overrides in text.mdx (#14211) (8136a84)
  • add mention of the useUploadHandlers error and steps to remedy it with a mention to monorepos (#14233) (8663024)

🔨 Build

🏡 Chores

🤝 Contributors

v3.60.0

16 Oct 16:48
b26129c

Choose a tag to compare

v3.60.0 (2025-10-16)

🚀 Features

  • accept multiple locales in fallbackLocale (#13822) (623a1b8)
  • adds settingsMenu to admin navigation sidebar (#14139) (ee8b3cf)
  • plugin-multi-tenant: allow collection access to be overridden via callback (#14127) (c40eec2)
  • plugin-multi-tenant: allow hasMany on tenant field overrides (#14120) (fb93cd1)
  • plugin-multi-tenant: user collection access overrides (#14119) (38b7a60)
  • richtext-lexical: add collection filtering to UploadFeature, refactor relationship hooks (#14111) (6defba9)
  • richtext-lexical: client-side block markdown shortcuts, code block (#13813) (07a1eff)

Localization

  • Multiple fallback locales - fallbackLocale now accepts an array of locales for queries and locale configs. Payload will check each locale in order until finding a value, eliminating the need for manual fallback handling. #13822

    /** Local API **/
      await payload.findByID({
        id,
        collection,
        locale: 'en',
        fallbackLocale: ['fr', 'es'],
      })
    
    /** REST API **/
      await fetch(`${baseURL}/api/${collectionSlug}?locale=en&fallbackLocale[]=fr&fallbackLocale[]=es`)
    
    /** GraphQL **/
      await restClient.GRAPHQL_POST({
        body,
        query: { locale: 'en', fallbackLocale: ['fr', 'es']},
      })
    
    /** Locale Configs **/
      locales: [
        {
          code: 'en',
          label: 'English',
          fallbackLocale: ['fr', 'es'],
        },
      ]

Admin UI

  • Settings menu in navigation - New admin.components.settingsMenu config option adds a gear icon above the logout button. Click to open a popup menu with custom admin-level utilities and actions that don't fit into collection or global navigation. #14139

    Screenshot 2025-10-14 at 11 43 37 AM

Multi-Tenant Plugin

  • Collection access overrides - New accessResultOverride callback allows modifying multi-tenant access control results per operation (read, create, update, delete, readVersions, unlock). Enables custom logic like allowing shared content across tenants. #14127

    multiTenantPlugin<ConfigType>({
      collections: {
        posts: {
          accessResultOverride: async ({ accessResult, accessKey, req }) => {
            // here is where you can change the access result or return something entirely different
            if (accessKey === 'read') {
              return {
                or: [
                  {
                    isShared: {
                      equals: true,
                    }
                  },
                  accessResult
                ]
              }
            } else {
              return accessResult
            }
          }
        }
      }
    })
  • Multiple tenants per document - Tenant field overrides now support hasMany relationships, allowing documents to belong to multiple tenants. #14120

  • User collection access overrides - New usersAccessResultOverride callback enables customizing access control on the users collection, overriding default tenant privacy when needed. #14119

    usersAccessResultOverride: ({
      accessKey: 'read', // 'create', 'read', 'update', 'delete', 'readVersions', 'unlock'
      accessResult: AccessResult, // the `AccessResult` type
      ...args, // AccessArgs
    }) => {
      // this is where you could adjust what gets returned here.
      if (accessKey === 'read') {
        return true // over simplified example
      }
    
      // default to returning the result from the plugin
      return accessResult
    }

Lexical Rich Text

  • Upload collection filtering - UploadFeature now supports disabledCollections and enabledCollections to control which collections appear in the upload drawer. Also refactors enabled relationships logic with cleaner useEnabledRelationships hook. #14111

  • Client-side markdown shortcuts & code blocks - Blocks with admin.jsx now support markdown shortcuts on the client (previously server-only). Includes pre-made CodeBlock component for use in BlocksFeature. Also fixes readOnly handling across nested fields. #13813

    Screenshot.2025-10-01.at.10.14.54.mp4

🐛 Bug Fixes

  • findDistinct by explicit ID paths in relationships and virtual fields (#14215) (2b1b6ee)
  • hasMany / polymorphic relationships to custom number IDs (#14201) (a3b3865)
  • hide fields with read: false in list view columns, filters, and groupBy (#14118) (bcd40b6)
  • validate Point Field to -180 to 180 for longitude and -90 to 90 for latitude (#14206) (13a1d90)
  • urls in upload sizes are not encoded (#14205) (747a049)
  • restoring trashed drafts with empty required fields fails validation (#14186) (3317207)
  • db-d1-sqlite: add missing blocksAsJSON property (#14103) (f14a38e)
  • db-mongodb: documents not showing in folders with useJoinAggregations: false (#14155) (e613a78)
  • db-mongodb: improve check for ObjectId (#14131) (32e2be1)
  • graphql: bump tsx version to get around esbuild vulnerability (#14207) (d7ec48f)
  • next: custom views not overriding built-in single-segment routes (#14066) (691f810)
  • plugin-multi-tenant: object reference mutations in addFilterOptionsToFields (#14150) (e62f1fe)
  • richtext-lexical: state key collisions when multiple TextStateFeatures are registered (#14194) (f01a6ed)
  • richtext-lexical: editor throws an error if OrderedList is registered but not UnorderedList or CheckList (#14149) (1fe75e0)
  • richtext-lexical: editing a copied inline block also modifies the original (#14137) (5bacb38)
  • richtext-lexical: correctly type field property of RenderLexical (#14141) (cd94f8e)
  • richtext-lexical: improve type autocomplete and assignability for lexical nodes (#14112) (a46faf1)
  • sdk: pagination is not passed to search params (#14126) (ee9f160)
  • storage-gcs: bump @google-cloud/storage for vulnerability (#14199) (1077aa7)
  • storage-r2: uploads with prefix don't work, add test/storage-r2 (#14132) (4fd4cb0)
  • templates: encoding and decoding slugs in website template (#14216) (cacf523)
  • templates: ecommerce seeding issue (#14196) (d65b8c6)

#...

Read more