feat!: move storage adapters to storage property instead of plugins for early initialisation#16596
Conversation
📦 esbuild Bundle Analysis for payloadThis analysis was generated by esbuild-bundle-analyzer. 🤖
Largest pathsThese visualization shows top 20 largest paths in the bundle.Meta file: packages/next/meta_index.json, Out file: esbuild/index.js
Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js
Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js
Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js
Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js
Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js
DetailsNext to the size is how much the size has increased or decreased compared with the base branch of this PR.
|
…ig-for-early-initilisation
…ig-for-early-initilisation
…ig-for-early-initilisation
There was a problem hiding this comment.
I think we need to do some deeper thinking on improving this pattern. I have concerns about whether this actually solves the pain point we want. The scenario I'm thinking of is:
- You have a plugin that adds some internal collections
my-plugin-coll-1 - You want the plugin to use a specific storage adapter
Right now, your storage adapter needs to know about the existence of this plugin's internal collection, which I think is quite clunky and not ideal.
I'd like us to consider having some sort of "registration" of storage adapters that can then be referenced by the plugin.
Let's get a discussion on the books for this.
DanRibbens
left a comment
There was a problem hiding this comment.
Needs docs in docs/migration-guide/v4.mdx
Migrate templates to 4.x APIs via @payloadcms/codemod plus manual fixes: - Move storage adapters from plugins to the top-level storage array (#16596) - Rewrite removed @payloadcms/next/{rsc,client} subpaths to @payloadcms/ui in import maps - Replace bare src/ imports with the @/ path alias - Drop the slug generic on Pages/Posts so defaultPopulate stays assignable to the collections array
# Overview The `build-and-test-templates` CI job was disabled while 4.x breaking changes landed, so the templates drifted and no longer build against current core packages. This updates each template to the new 4.x APIs so they build again. CI for the re-enabled job: [#16880](#16880). ## Key Changes - **Storage adapters moved from `plugins` to `storage`** - 4.x initializes storage adapters from a top-level `storage` array instead of `plugins` (#16596). `vercelBlobStorage` / `r2Storage` calls were relocated in `with-vercel-mongodb`, `with-vercel-postgres`, `with-vercel-website`, and `with-cloudflare-d1`. This was the source of the `TypeError: plugin is not a function` failures. Applied with `@payloadcms/codemod`'s `migrate-storage-adapters-to-config`. - **Import maps point at `@payloadcms/ui` instead of removed `@payloadcms/next` subpaths** - The `@payloadcms/next/rsc` and `@payloadcms/next/client` subpaths were removed; generated import maps now reference `@payloadcms/ui/rsc` and `@payloadcms/ui`. Applied with `@payloadcms/codemod`'s `migrate-next-subpath-exports` across all templates. - **Bare `src/` imports replaced with the `@/` path alias** - Website-based templates imported from `src/...`, which no longer resolves under Turbopack. Switched to the configured `@/` alias (maps to `./src/*`). - **Slug generic dropped on `Pages` / `Posts` (TypeScript 6 regression workaround)** - The documented `CollectionConfig<'pages'>` + `defaultPopulate` pattern compiled under TypeScript 5.7 (3.x) but not under TypeScript 6.0.3 (the #16692 bump): the generated select interface is no longer assignable to the `SelectType` that the `collections` array element expects. Dropping the generic lets `defaultPopulate` fall back to `SelectType` so the templates build, at the cost of field-name checking on `defaultPopulate`. This is a core type regression that affects any 4.x project using the pattern under TS 6, so the real fix belongs in core; the templates carry a commented workaround to be reverted once that lands. ## Design Decisions Most changes were applied with `@payloadcms/codemod` rather than by hand, so the same transforms users will run produce the same result. Import maps are left as the minimal subpath rewrite rather than a full local regeneration, since `payload build` regenerates them during the build. Scope is template builds. All six matrix templates build with packed local packages, verified locally via `script:pack --all` + `build-template-with-local-pkgs`. The remaining E2E failures on `blank` and `website` (`chunk.reason.enqueueModel is not a function` when loading the admin under `next dev`) are a pre-existing runtime issue, present before this change and unrelated to the build fixes. Only the workspace templates (`blank`, `website`, `ecommerce`) run E2E in this job; `pnpm --filter` does not match the non-workspace templates, so their E2E and int steps currently no-op. --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1215426886664378
Summary
storageconfig key for Payload, letting storage adapters (@payloadcms/storage-s3,-azure,-gcs,-r2,-vercel-blob,-uploadthing) be declared at the top level of the config rather than insidepluginsStorageAdapterobject ({ name, collections, init }) instead of aPluginfunction;buildConfigcallsadapter.init(config)before any plugins run, guaranteeing upload hooks are wired after plugins executemigrate-storage-adapters-to-configcodemod to automate migration:npx @payloadcms/codemod --transform migrate-storage-adapters-to-configMigration
Existing
pluginsusage continues to work unchanged. To adopt the new API, move storage adapters out ofpluginsand intostorage:Run the codemod to automate this: