Payload CMS Release: 3.0.0

Tag Name: v3.0.0

Release Date: 11/19/2024

Payload CMS LogoPayload CMS

Payload CMS is a modern, self-hosted headless content management system built with TypeScript, Node.js, and MongoDB. It's designed specifically for developers who want full control over their content management system while maintaining a powerful admin interface for content editors.

TL;DR

Payload CMS 3.0: Next.js App Router Integration & Major Architecture Overhaul

Payload CMS 3.0 represents a complete architectural transformation from an Express + React Router SPA to a Next.js App Router + React Server Components implementation. This major release enables serverless deployment, seamless Next.js integration, and introduces powerful new features like Join fields, Select API, Jobs Queue, and more. The admin UI has been refreshed, and numerous performance improvements and developer experience enhancements have been added.

This is a breaking change release that requires migration from v2. The new architecture allows for deploying your entire project (frontend and backend) in one app, with full support for serverless environments like Vercel.

Highlight of the Release

    • Complete re-architecture from Express + React Router SPA to Next.js App Router + React Server Components
    • Serverless deployment support on platforms like Vercel
    • New Join field for bi-directional relationships and better database schema control
    • Select API for retrieving only specific fields when querying
    • Built-in Jobs Queue for background processing without third-party dependencies
    • Postgres and SQLite database adapters now stable
    • Live Preview with server components support
    • Document locking to show when someone is currently editing a document
    • Bulk upload functionality and support for hasMany upload fields
    • Ability to publish individual locales one at a time

Migration Guide

Migration from v2 to v3

Payload 3.0 represents a significant architectural change from v2. Here are the key steps to migrate:

Project Structure Changes

  1. Install Next.js and update Payload:

    npm install next@latest payload@latest
    
  2. Create Next.js App Router structure: Create the following directory structure:

    app/
      (payload)/
        [[...payload]]/
          page.tsx
        layout.tsx
      api/
        [...nextjs]/
          route.ts
    
  3. Update your Payload config:

    - import { buildConfig } from 'payload/config'
    + import { buildConfig } from 'payload'
    
    export default buildConfig({
      // Your config here
    })
    
  4. Create Next.js config:

    // next.config.js
    import { withPayload } from '@payloadcms/next'
    
    export default withPayload({
      // Your Next.js config here
    })
    

API Changes

  1. Update imports:

    - import { PayloadRequest } from 'payload/types'
    + import { PayloadRequest } from 'payload'
    
  2. Update Local API usage:

    - import { getPayload } from 'payload/dist/payload'
    + import { getPayload } from 'payload'
    
    const payload = await getPayload()
    
  3. Update custom components:

    - import { useField } from 'payload/components/forms'
    + import { useField } from '@payloadcms/ui'
    
  4. Update custom views:

    admin: {
      components: {
        views: {
    -      Account: MyAccountComponent,
    -      Dashboard: MyDashboardComponent,
    +      account: MyAccountComponent,
    +      dashboard: MyDashboardComponent,
        }
      }
    }
    
  5. Update server functions: Add the following to your root layout file:

    import type { ServerFunctionClient } from 'payload'
    import { handleServerFunctions } from '@payloadcms/next/utilities'
    
    const serverFunctions: ServerFunctionClient = async function (args) {
      'use server'
      return handleServerFunctions({
        ...args,
        config,
        importMap,
      })
    }
    
    const Layout = ({ children }: Args) => (
      <RootLayout
        config={config}
        importMap={importMap}
        serverFunctions={serverFunctions}
      >
        {children}
      </RootLayout>
    )
    
  6. Update form state handling:

    - import { getFormState } from '@payloadcms/ui'
    - const { state } = await getFormState({
    -   apiRoute: '',
    -   body: {
    -     // ...
    -   },
    -   serverURL: ''
    - })
    
    + const { getFormState } = useServerFunctions()
    + const { state } = await getFormState({
    +   // ...
    + })
    
  7. Update cloud storage adapters:

    azureStorage({
      collections: {
    -   [Media.slug]: true,
    +   media: true,
      },
    })
    
  8. Update MongoDB relationships: For projects with existing data having versions enabled, or relationship or upload fields, create the predefined migration:

    payload migrate:create --file @payloadcms/mongodb/relationships-v2-v3
    

For a complete migration guide, please refer to the official migration documentation.

Upgrade Recommendations

Upgrade Recommendation

Who should upgrade?

  • All Payload users should plan to upgrade to v3 as it represents the future direction of Payload CMS
  • Next.js users will benefit immediately from the tight integration
  • Users needing serverless deployment should prioritize upgrading

When to upgrade?

  • New projects: Start with v3 immediately
  • Existing projects: Plan a migration when you have sufficient development time to handle breaking changes
  • Production applications: Test thoroughly in a staging environment before upgrading

How to upgrade?

  1. Read the migration guide thoroughly before starting
  2. Create a new branch for your migration work
  3. Update dependencies to the latest versions
  4. Restructure your project to follow the Next.js App Router pattern
  5. Update your imports according to the new package structure
  6. Test thoroughly before deploying to production

Special considerations:

  • If using MongoDB with relationships or uploads, run the provided migration script
  • If using custom components or plugins, they will need to be updated
  • If using custom server code, you'll need to adapt to the Next.js API routes pattern
  • If using TypeScript with strict mode, pay attention to type changes

The upgrade process requires significant changes to your project structure, but the benefits in terms of performance, features, and deployment options make it worthwhile for most users.

Bug Fixes

  • Fixed issues with document locking and user permissions
  • Corrected package import paths for live preview test
  • Fixed MongoDB adapter to properly handle relationship IDs as ObjectIDs
  • Resolved issues with plugin-search when localization is enabled
  • Fixed join field handling with singular collection names
  • Corrected buttons in the bulk upload drawer
  • Fixed issues with custom views and notFound page
  • Improved performance in bulk upload
  • Fixed spelling errors and formatting issues in documentation
  • Resolved issues with GraphQL adding extra password fields when running mutations
  • Fixed description undefined error on empty tabs array
  • Corrected return type of findByID with strict: true
  • Increased z-index of ReactSelect to prevent UI overlap issues
  • Fixed SEO plugin issues with localized labels
  • Resolved problems with locked documents with read access for users
  • Fixed width issues on document locked modal content
  • Fixed select functionality with unnamed tabs
  • Corrected website template error inside the populateAuthors hook
  • Fixed querying relationships by id path with REST
  • Resolved invalid select type with strictNullChecks: true
  • Fixed GraphQL missing options route causing failed CORS preflight checks
  • Addressed prefetch causing stale data issues
  • Fixed updatedAt field in locked-docs collection being updatable by non-owner
  • Ensured upload field updates reflect in edit popup changes
  • Fixed JSON fields display and height issues
  • Corrected type augmentation of RequestContext
  • Fixed custom endpoints with method: 'put'
  • Resolved cases of false positive identification of custom ID fields

New Features

Architectural Changes

  • Payload now installs fully in any Next.js app router
  • Deploy your entire project (frontend and backend) in one app
  • Serverless deployment support on platforms like Vercel
  • Use Payload Local API in Server Components and Server Functions
  • Postgres, Live Preview, and Lexical are now marked as stable
  • Cleaned up exports and modular package structure (ui, next, translations, graphql)
  • Converted to ESM project
  • Server-side HMR works out of the box (no more nodemon)

Major Features

  • Join Field: Bi-directional relationships, better database schema control
  • Select API: Choose specific fields when querying using Local API
  • Jobs Queue: Background jobs with no third-party dependencies
  • Populate/DefaultPopulate API: Control which fields are retrieved when populating relationships
  • Lexical Blocks and Inline Blocks: Make Payload Blocks available in Lexical as rich text features
  • SQLite Database Adapter: Now available for simpler deployments
  • Vercel Postgres Adapter: Specifically for serverless deploys on Vercel
  • Live Preview Server Components: Enhanced preview capabilities
  • Document Locking: Shows if someone is currently editing a document
  • Bulk Upload: Improved file upload capabilities
  • HasMany Upload Fields: Support for multiple file uploads in a single field
  • Individual Locale Publishing: Publish specific locales one at a time
  • Lexical Table Support: Enhanced rich text editing capabilities

Additional Features

  • New Payload logo
  • Resend email adapter
  • Postgres now saves single, monomorphic relationships directly in a column
  • GraphQL abstracted into a specific Next.js route handler
  • React Compiler in Payload build pipeline
  • Run migrations on init (helpful for long-running servers)
  • New Local API operations: count, countVersions, countGlobalVersions, upsert
  • baseListFilter function for enforced list view filters
  • Lexical fixed toolbar option
  • Optimized relational DB storage for relations
  • Postgres point field and deep JSON querying support
  • Custom Drizzle schema support
  • Fully typed i18n t function
  • Focal point data storage on uploads
  • Login with username rather than email
  • Custom server/client props for custom components
  • Email adapter pattern with optimized Resend HTTP client
  • Optimized /access permissions results
  • Multiple field sorting
  • MongoDB now saves ObjectID for relationships
  • Log level customization
  • Common errors downgraded to info level
  • Replaced react-toastify with sonner
  • True "virtual" fields via virtual: true
  • Filename customization before upload
  • Locale indicators on localized field labels
  • Scoped CSS with payload-default layer
  • Document duplicate/delete from drawers

Security Updates

  • Protected the /api/access endpoint behind authentication
  • Sanitized access endpoint results to make them more secure and significantly smaller
  • Improved handling of document locking permissions
  • Enhanced authentication flows and permission checks
  • Fixed issues with locked documents and user access controls
  • Improved CORS handling for GraphQL endpoints
  • Better sanitization of relationship IDs in database operations

Performance Improvements

  • Optimized the way relational databases store relations
  • Reduced and optimized the shape of /access permissions results
  • Improved MongoDB performance by using ObjectID for relationships
  • Enhanced Lexical editor performance with reduced rerendering
  • Reduced network requests from blocks in rich text editors
  • Removed unnecessary field styles from initial page response
  • Optimized initial page responses by removing duplicative styles
  • Improved form submission to reduce layout shift
  • Reduced HTML bloat by removing undefined props from RSC requests
  • Removed i18n.supportedLanguages from client config to reduce network payload
  • Upgraded dependencies to reduce bundle size and total number of dependencies
  • Implemented better abort controller logic for server functions
  • Improved handling of bulk uploads to prevent conflicts and resource overuse
  • Enhanced database query performance with the Select API
  • Added support for deep querying on JSON and rich text fields in Postgres
  • Improved caching and state management for list columns

Impact Summary

Payload CMS 3.0 represents a fundamental architectural shift from Express to Next.js, bringing significant improvements in deployment flexibility, developer experience, and feature set. This major release enables serverless deployment on platforms like Vercel, seamless integration with Next.js applications, and introduces powerful new features like Join fields, Select API, and a built-in Jobs Queue.

The impact is substantial across different user types:

  1. For developers, this release provides a more modern, modular architecture with improved TypeScript support, better performance, and powerful new APIs. However, it requires significant migration work for existing projects.

  2. For content editors, the refreshed admin UI, bulk upload functionality, document locking, and improved rich text editing with Lexical enhancements deliver a better content management experience.

  3. For DevOps engineers, the ability to deploy Payload serverless, use SQLite or Vercel Postgres, and benefit from server-side HMR simplifies infrastructure management.

  4. For plugin developers, the new modular architecture with separate packages for UI, Next.js integration, translations, and GraphQL provides more flexibility but requires updates to existing plugins.

While the breaking changes are significant and require careful migration planning, the benefits in terms of deployment options, performance improvements, and new capabilities make this a compelling upgrade for most Payload users. The shift to Next.js App Router and React Server Components aligns Payload with modern React development practices and opens up new possibilities for building integrated content management solutions.

Full Release Notes

This is a major release that includes a re-architecture of Payload from an Express + React Router SPA to the Next.js App Router + RSCs. In addition to this architectural change, we've also shipped a ton of large features, miscellaneous fixes, and DX improvements.

Architectural changes

  • Payload now installs fully in any Next.js app router
  • You can now deploy your entire project (frontend and backend) in one app
  • Payload can now be deployed serverless on platforms like Vercel
  • Everything Payload does now works seamlessly within any Next.js project
  • You can now use the Payload Local API in Server Components and Server Functions
  • Postgres, Live Preview, and Lexical have been marked as stable
  • All Payload exports have been significantly cleaned up and organized
  • Payload is now an ESM project
  • Payload is now modular, and we now publish new packages ui, next, translations, and graphql
  • The Payload config is now server-side only, and works in any Node environment
  • Server-side HMR works out of the box - removing the need for nodemon

Large features

  • Join field - bi-directional relationships, more control over the database schema, and more
  • Select API - select specific fields when querying using Local API
  • Jobs Queue - background jobs fully supported in Payload with no third-party dependencies
  • Populate / DefaultPopulate API - determine which fields should be retrieved when Payload populates relationships
  • Lexical blocks and inline blocks - easily make Payload Blocks available in Lexical as custom rich text features
  • SQLite database adapter now available
  • Vercel Postgres database adapter released, specifically for serverless deploys on Vercel
  • Live Preview server components support
  • Admin UI has been refreshed
  • hasMany upload fields are now supported
  • Bulk upload has been added
  • Document Locking pattern has been implemented, which shows if someone is currently editing a document
  • Ability to publish individual locales one at a time has been added
  • Lexical now has Table support

Small but still important features

  • New Payload logo (thanks Candycode!)
  • New Resend email adapter is now available
  • Postgres now saves single, monomorphic relationships directly in a column rather than in _rels table
  • GraphQL has been abstracted into a specific Next.js route handler, and no longer affects Payload initialization at all
  • React Compiler has been introduced into Payload build pipeline
  • You can now run migrations on init, rather than only in CI (helpful for long-running servers)
  • New Local API operations - count, countVersions, countGlobalVersions, upsert
  • Adds baseListFilter function to allow enforced list view filters based on user
  • Lexical fixed toolbar option has been added
  • Optimized the way that relational DBs store relations
  • Postgres point field is now supported
  • Postgres deep JSON querying is now supported
  • Cuztomize Drizzle schema by passing in your own, which is handled outside of Payload
  • Fully typed i18n t function
  • Focal point data is now stored on uploads
  • Adds ability to login with username rather than email
  • New pattern for passing custom server / client props to custom components
  • Email adapter pattern, including optimized Resend HTTP client
  • Reduced / optimized the shape of /access permissions results
  • Allows sorting by multiple fields
  • MongoDB now saves ObjectID for relationships
  • Adds more control over log level customization
  • Downgrades common errors like NotFound or Forbidden to info
  • Swaps out react-toastify for sonner
  • True "virtual" fields via virtual: true
  • Adds ability to customize filenames before upload
  • Adds locale indicators to localized field labels
  • Scope all payload css to payload-default layer
  • Document duplicate / delete from drawers

⚠️ BREAKING CHANGES

This release includes breaking changes. In order to update from version 2 to 3, please review the migration docs.

🤝 Contributors

Statistics:

File Changed300
Line Additions94,350
Line Deletions4,788
Line Changes99,138
Total Commits250

User Affected:

  • Need to migrate existing Payload v2 projects to the new architecture
  • Can now deploy Payload serverless on platforms like Vercel
  • Can use Payload Local API directly in Next.js Server Components
  • Benefit from improved TypeScript support and DX improvements
  • Can use new features like Join fields, Select API, and Jobs Queue

Contributors:

kendelljosephDanRibbensr1tsuujmikrutpaulpopusakhrarovsaiddenolfeKonsequanzhengGregorGabricagrippa1994PatrikKozakGermanJablovahacreativeJesperWeMrFriggoabernhjacobsfletchtyteen4a03jessrynkarjavierlinkedtylandavismiguel2650AlessioGrsteventsvetkovnathanclevengerruymonncaminataJarrodMFleschtak-ambossfranciscolourencoOrtimismikkelwfmattddeansandren