Migration Guide (v2.x > v3.x) #6929
Replies: 12 comments 3 replies
-
Environment variables
|
Beta Was this translation helpful? Give feedback.
-
Payload Config🚨 Depreceated properties:
🚨 The 🚨 The You can uninstall them from your project by: 🚨 The Plugins that need to inject global styles should do so via the provider config at Here is a basic example of a provider: import React from 'react'
import './plugin-styles.scss'
export const MyPluginStylesProvider: React.FC<{children?: any}>= ({ children }) = {
return (
<React.fragment>
{children}
</React.fragment>
)
} Then in your admin: {
components: {
providers: [
MyPluginStylesProvider
]
}
}, 🚨 The You can now add your own custom HTML directly into the 🚨 Remove any Rate Limit configuration. Rate limiting has been removed from Payload. If you were using it, you will need to implement your own rate limiting middleware by using a custom server (Express or similar) 🚨 The ❌ Old {
admin: {
favicon: 'path-to-favicon.svg'
}
} ✅ New {
// ..
admin: {
icons: [{
path: 'path-to-favicon.svg',
sizes: '32x32'
}]
}
} This change was made to allow compatibility with Next.js—learn more about how icons are generated here 🚨 The To migrate, simply move those two keys as follows: ❌ Old {
admin: {
logoutRoute: '/custom-logout',
inactivityRoute: '/custom-inactivity'
}
} ✅ New {
admin: {
routes: {
logout: '/custom-logout',
inactivity: '/custom-inactivity'
}
}
} 🚨 The {
admin: {
meta: {
ogImage: ''
}
}
} ✅ New {
admin: {
meta: {
openGraph: {
images: []
}
}
}
} 🚨 Your secret key should now be passed directly to the This used to be passed to the buildConfig({
// Rest of your config
secret: process.env.PAYLOAD_SECRET
}) 🚨 Email functionality has been abstracted out into email adapters.
Instead, their new type is
This is is a property specific to React Router, not Next.js. If you need to do fancy matching similar to this, use a custom tab that fires of some hooks, i.e.
Sharp is no longer required and should only be defined if you have configured image resizing or cropping
The buildConfig({
custom: {
someProperty: 'value' // Available in server only
},
admin: {
custom: {
name: 'Customer portal' // Available in server and client
}
},
}) |
Beta Was this translation helpful? Give feedback.
-
Collections🚨 Deprecated properties:
🚨 The Instead, you should use the new ❌ Old {
admin: {
hooks: {
beforeDuplicate: async ({ data }) => {
return {
...data,
title: `${data.title} - Copy`
}
}
}
}
} ✅ New {
admin: {...},
fields: [
{
name: 'title',
type: 'text',
admin: {
hooks: {
beforeDuplicate: async ({ data }) => {
return {
...data,
title: `${data.title} - Copy`
}
}
}
}
}
]
} 🚨 The ❌ Old {
admin: {
components: {
views: {
Edit: {
Tab: {
pillLabel: '',
},
},
},
},
},
} ✅ New {
admin: {
components: {
views: {
Edit: {
Tab: {
Pill: MyPill,
},
},
},
},
},
} |
Beta Was this translation helpful? Give feedback.
-
FieldsBreaking changes:
* This is because we cannot pass your import React from 'react'
import { useFieldProps, useFormFields } from '@payloadcms/ui'
import type { DescriptionComponent } from 'payload'
export const CustomFieldDescriptionComponent: DescriptionComponent = () => {
const { path } = useFieldProps()
const { value } = useFormFields(([fields]) = fields[path])
return (
<div>
{`Component description: ${path} - ${value}`}
</div>
)
}
export const CustomFieldLabelComponent: LabelComponent = () => {
const { path } = useFieldProps()
const { value } = useFormFields(([fields]) =fields[path])
return (
<div>
{`Component label: ${path} - ${value}`}
</div>
)
}
If using a custom component, you must now get the data yourself via the import React from 'react'
import { useTableCell } from '@payloadcms/ui/elements/Table'
export const CustomCellComponent: CellComponent = () => {
const { cellData, rowData } = useTableCell()
return (
<div>
{`Component cell: ${cellData}`}
</div>
)
}
❌ Old: {
type: 'array',
admin: {
components: {
RowLabel: ({ data }) => {
console.log(data)
return data?.title || 'Untitled'
},
}
}
} ✅ New: {
type: 'array',
admin: {
components: {
RowLabel: ArrayRowLabel
}
}
} Example custom Row Label component: 'use client'
import React from 'react'
import type { RowLabelComponent } from 'payload'
import { useRowLabel } from '@payloadcms/ui'
export const ArrayRowLabel: RowLabelComponent = () ={
const { data } = useRowLabel<{ title: string }>()
return (
<div>{data.title || 'Untitled'}</div>
)
}
This was changed for improved semantics. If you were previously importing this type in your own application, simply change the import name: ❌ Old import type { Fields } from 'payload' ✅ New import type { FormState } from 'payload' |
Beta Was this translation helpful? Give feedback.
-
Req
As a result, there may be minor differences in the properties and methods available on the |
Beta Was this translation helpful? Give feedback.
-
HooksThese changes affect the following properties:
Now, you can get title directly from document info context, i.e.
This is because the configs themselves are not serializable and so they cannot be thread through to the client, i.e. the
This is because the config itself is not serializable and so it is not able to be thread through to the client, i.e. the
Instead you can use the
|
Beta Was this translation helpful? Give feedback.
-
Custom Components
If you were previously importing components into your app from the
import { Button } from '@payloadcms/ui' NOTE: Payload pre-bundles its UI package for you in order to keep compile times as low as possible for end-user Payload developers. If you are importing components to re-use in the Payload admin panel, you should import them directly from either If you are importing components for use in your frontend, outside of the admin panel, then you should import components from their more deeply nested individual export location, such as All Custom Components are now server-rendered, and therefore, cannot use state or hooks directly unless you declare the component as a Client Component manually. If you're using a Custom Component in your app that requires state or hooks, define your component in a separate file with the |
Beta Was this translation helpful? Give feedback.
-
Descriptions and LabelsSeveral
|
Beta Was this translation helpful? Give feedback.
-
Custom EndpointsOverview of changes:
Learn more about how to create custom endpoints in the Next.js docs.
❌ Old {
path: '/whoami/:parameter',
method: 'post',
handler: (req, res) => {
res.json({
parameter: req.params.parameter,
name: req.body.name,
age: req.body.age,
})
}
} ✅ New {
path: '/whoami/:parameter',
method: 'post',
handler: (req) => {
return Response.json({
parameter: req.routeParams.parameter,
// ^^ `params` is now `routeParams`
name: req.data.name,
age: req.data.age,
})
}
}
❌ Before {
path: '/whoami/:parameter',
method: 'post',
handler: async (req) => {
return Response.json({
name: req.data.name, // data will be undefined
})
}
} ✅ After import { addDataAndFileToRequest } from '@payloadcms/next/utilities'
{
path: '/whoami/:parameter',
method: 'post',
handler: async (req) => {
// mutates req, must be awaited
await addDataAndFileToRequest(req)
return Response.json({
name: req.data.name, // data is now available
})
}
}
❌ Old {
path: '/whoami/:parameter',
method: 'post',
handler: async (req) => {
return Response.json({
// will be undefined
fallbackLocale: req.fallbackLocale,
locale: req.locale,
})
}
} ✅ New import { addLocalesToRequest } from '@payloadcms/next/utilities'
{
path: '/whoami/:parameter',
method: 'post',
handler: async (req) => {
// mutates req
addLocalesToRequest(req)
return Response.json({
fallbackLocale: req.fallbackLocale,
locale: req.locale,
})
}
} |
Beta Was this translation helpful? Give feedback.
-
i18n
❌ Old const { i18n, t } = useTranslation('general')
return <p>{t('cancel')}</p> ✅ New const { i18n, t } = useTranslation()
return <p>{t('general:cancel')}</p>
Example translation string: "loggedInChangePassword": "To change your password, go to your <0>account</0> and edit your password there." ❌ Old <Trans i18nKey="loggedInChangePassword" t={t}>
<Link to={`${admin}/account`}>account</Link>
</Trans> ✅ New <Translation
t={t}
i18nKey="authentication:loggedInChangePassword"
elements={{
'0': ({ children }) => <Link href={`${admin}/account`} children={children} />,
}}
/> |
Beta Was this translation helpful? Give feedback.
-
Uploads
|
Beta Was this translation helpful? Give feedback.
-
PluginsAll plugins have been standardized to use named exports (as opposed to default exports). Most also have a suffix of ❌ Old import seo from '@payloadcms/plugin-seo'
import stripePlugin from '@payloadcms/plugin-stripe' ✅ New import { seoPlugin } from '@payloadcms/plugin-seo'
import { stripePlugin } from '@payloadcms/plugin-stripe' |
Beta Was this translation helpful? Give feedback.
-
Payload v3.0 is a major release with breaking changes. This migration guide will cover:
3.a. Moving your existing app to a new 3.0 template
3.b. Updating your existing app
What changed?
The biggest change of 3.0 is the move to Next.js - the Admin Panel and all core Payload functionality is now fully built with Next.js.
Key changes:
@payloadcms/ui
package'use client'
The above are not all breaking changes and will not all be applicable to you, however you should still briefly review them to ensure you are aware of the changes and how they may affect your app.
3.0 Documentation
Documentation for 3.0 (beta) can be found on the Payload Website. These docs are actively being built out.
Migrating from 2.0 to 3.0
To migrate your existing app, you can either:
OR
Option 1 - Move your existing app to a new 3.0 template
Copy your existing
payload.config
and all dependent files to the new app, review the Payload Config breaking changes outlined here and update as necessary. NOTE - TypeScript should be very helpful as you make sure your config is compatible with Payload 3.0. Just look through your files and try to spot any TypeScript errors after updating Payload and its sibling packages.Review the collection changes outlined here and update.
If you were using any custom components, endpoints, hooks, or plugins, make sure to update them to the new structure. See all the breaking changes outlined below.
Install any additional dependencies you were using in your 2.0 app
Run your app and test that everything is working as expected
If you are facing errors at this stage, review the remaining breaking changes outlined below or reach out to the Payload team for support.
Option 2 - Update your existing app to 3.0
You'll also need to update your database adapter to use the same version as the other Payload packages that have been updated.
Add the (payload) folder and required files:
As Payload 3.0 is now fully Next.js native, you will need to add the required files for the admin UI and route handlers.
We have consolidated all admin views into a single
page.tsx
and consolidated the API endpoints into singleroute.ts
files for simplicity and performance.The benefit of this structure is that you only need to compile the admin UI / REST API / GraphQL API a single time then it will be served from the server.
This means that the admin UI will be faster and more responsive, and the server will be more efficient.
Your Next.js
/app
folder should include the following:/(payload)
/admin/[[...segments]]
page.tsx
not-found.tsx
/api
/[...slug]
route.ts
/graphql
route.ts
/graphql-playground
route.ts
custom.scss
layout.tsx
We recommend you copy the entire (payload) folder from the blank 3.0 template, or you can create them manually.
You can find the template on GitHub or use the following command to create a new app and copy from there:
Remove the
server.ts
file:The purpose of the
server.ts
file in 2.0 was to boot up an Express app, which was then used to serve the admin panel and API routes. However, since we are no longer relying on Express for this, and instead using Next.js, the entire file can be removed.If you were passing any custom code in the
server.ts
file, you should migrate this to Payload 3.0 / Next.js-compatible code. For example, if you were performing any startup actions, you can now place those actions in your Payload config'sonInit
method. Any Express middleware should be refactored into either Next.js middleware, or into Payload hooks. Custom Express routes should be transformed into Next.js Route Handlers.NOTE: You can still use Express with Next.js by creating a custom server file in the root of your app, i.e.
server.js
and using it as a custom server with Next.js' Custom Server functionality. That way, if you have a significant amount of Express-specific middleware and endpoints, you can still continue to use them accordingly. Learn more about this from the Next.js documentation.next.config.js
,tsconfig.json
,package.json
andpayload.config.ts
To start, copy your existing
next.config.js
file to the new app, then you'll need to update the file to an ESM file.You can do this by either:
- Renaming the file from
next.config.js
tonext.config.mjs
or
- Adding the
type: module
property to yourpackage.json
fileAfter you have updated the file to an ESM file, you then need to import and wrap the export in the
withPayload
function. This function is required for Payload to run and ensures compatibility with other packages that Payload uses such asdrizzle-kit
,sharp
,pino
, andmongodb
.page.tsx
files androute.ts
files within the(app)
folder use this alias to load your config and make it available to your application.Next, if necessary, you should update the
moduleResolution
fromnode
tobundler
. This mode supports package.json "imports" and "exports", but unlike the Node.js resolution modes,bundler
does not require file extensions on relative import paths. Read more about this in the TypeScript documentation.package.json: Update existing
scripts
to include the newdev
,build
andstart
commands:payload.config.ts: There are a few different changes to the
payload.config.ts
file in 3.0. Copy your existing file to the new app and review the breaking changes outlined here then update as necessary.Collections: Migrate and update your existing collections, review the collection breaking changes outlined here.
If you were using any custom components, endpoints, hooks, or plugins, make sure to update them to the new structure. See all the breaking changes outlined here.
If errors persist, review the remaining breaking changes outlined below and if you still need assistance, reach out to the Payload team for support.
Breaking Changes
All breaking changes are divided into the following categories:
❗ Not all of these changes will be applicable to you, and you may not need to make all of these changes.
We recommend that you get the proper files in place, and then look at your config and dependencies for TypeScript errors, and tackle them by resolving one by one.
Beta Was this translation helpful? Give feedback.
All reactions