Skip to content

feat: framework-agnostic server APIs#16753

Draft
jacobsfletch wants to merge 5 commits into
feat/admin-router-adapterfrom
refactor/server-adapter-abstraction
Draft

feat: framework-agnostic server APIs#16753
jacobsfletch wants to merge 5 commits into
feat/admin-router-adapterfrom
refactor/server-adapter-abstraction

Conversation

@jacobsfletch
Copy link
Copy Markdown
Member

@jacobsfletch jacobsfletch commented May 27, 2026

Decouples plugins and server components from Next.js APIs, e.g. headers, cookies, server-side navigation, etc. This way we can fully support alternative React frameworks other than Next.js, e.g. TanStack.

This includes:

  • getCookies
  • getHeaders
  • redirect
  • notFound

These methods are now accessible behind a new req.server prop. Each framework is responsible for adapting its own methods into this standard format.

Before, you'd use direct imports from next/*:

import { cookies, headers } from 'next/headers.js'
import { notFound, redirect } from 'next/navigation.js'

export const MyPluginView = async ({ payload }: ServerProps) => {
  const reqHeaders = await headers()
  const reqCookies = await cookies()
  const session = reqCookies.get('session')?.value

  if (!session) {
    redirect('/login')
  }
}

After, there are now framework-agnostic methods accessible via req.server:

export const MyPluginView = async ({ req }: ServerProps) => {
  const reqHeaders = await req.server.getHeaders()
  const reqCookies = await req.server.getCookies()
  const session = reqCookies.get('session')?.value

  if (!session) {
    req.server.redirect('/login')
  }
}

In custom server components, this is provided to you as a new server prop.

To write a server adapter, you must provide these methods using your framework's APIs.

Here's an example of what a Next.js server adapter might look like (simplified):

import type { ServerAdapter } from 'payload'

import { headers as getNextHeaders } from 'next/headers.js'

import {
  notFound as nextNotFound,
  redirect as nextRedirect,
} from 'next/navigation.js'

export const nextServerAdapter: ServerAdapter = {
  getHeaders: () => getNextHeaders(),
  notFound: () => nextNotFound(),
  redirect: (path) => nextRedirect(path),
  // ...
}

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

📦 esbuild Bundle Analysis for payload

This analysis was generated by esbuild-bundle-analyzer. 🤖

Meta File Out File Size (raw) Note
packages/next/meta_index.json esbuild/index.js 1.04 MB 🆕 Added
packages/payload/meta_index.json esbuild/index.js 1.41 MB 🆕 Added
packages/payload/meta_shared.json esbuild/exports/shared.js 192.51 KB 🆕 Added
packages/richtext-lexical/meta_client.json esbuild/exports/client_optimized/index.js 304.12 KB 🆕 Added
packages/ui/meta_client.json esbuild/exports/client_optimized/index.js 1.25 MB 🆕 Added
packages/ui/meta_shared.json esbuild/exports/shared_optimized/index.js 18.56 KB 🆕 Added
Largest paths These visualization shows top 20 largest paths in the bundle.

Meta file: packages/next/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████████▋ }}}$ 82.9%, 861.29 KB
dist/views/Version ${{\color{Goldenrod}{ █▎ }}}$ 5.0%, 51.56 KB
dist/views/Dashboard ${{\color{Goldenrod}{ ▌ }}}$ 2.1%, 21.75 KB
dist/views/Document ${{\color{Goldenrod}{ ▍ }}}$ 1.6%, 16.73 KB
dist/views/List ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 15.46 KB
dist/elements/Nav ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 10.26 KB
dist/views/Root ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 9.93 KB
dist/views/API ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.13 KB
dist/views/Account ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.08 KB
dist/views/Versions ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.74 KB
dist/elements/DocumentHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.75 KB
dist/views/Login ${{\color{Goldenrod}{ }}}$ 0.4%, 4.57 KB
dist/layouts/Root ${{\color{Goldenrod}{ }}}$ 0.3%, 3.56 KB
dist/views/ForgotPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 3.15 KB
dist/views/CreateFirstUser ${{\color{Goldenrod}{ }}}$ 0.3%, 3.02 KB
dist/views/ResetPassword ${{\color{Goldenrod}{ }}}$ 0.2%, 2.42 KB
dist/templates/Default ${{\color{Goldenrod}{ }}}$ 0.2%, 2.04 KB
dist/views/Logout ${{\color{Goldenrod}{ }}}$ 0.2%, 1.96 KB
dist/views/Verify ${{\color{Goldenrod}{ }}}$ 0.1%, 1.31 KB
dist/utilities/initReq.js ${{\color{Goldenrod}{ }}}$ 0.1%, 1.15 KB
(other) ${{\color{Goldenrod}{ ████▎ }}}$ 17.1%, 178.26 KB

Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ █████████████████ }}}$ 68.4%, 959.51 KB
dist/fields/hooks ${{\color{Goldenrod}{ ▊ }}}$ 3.1%, 44.07 KB
dist/collections/operations ${{\color{Goldenrod}{ ▋ }}}$ 2.9%, 40.23 KB
dist/versions/migrations ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 18.50 KB
dist/auth/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 15.63 KB
dist/fields/config ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 13.41 KB
dist/globals/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 13.40 KB
dist/utilities/configToJSONSchema.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 13.13 KB
dist/queues/operations ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 12.63 KB
dist/fields/validations.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.57 KB
dist/collections/config ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 9.53 KB
dist/bin/generateImportMap ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 9.44 KB
dist/config/orderable ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.92 KB
dist/uploads/fetchAPI-multipart ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.80 KB
dist/index.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.77 KB
dist/hierarchy/utils ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 7.65 KB
dist/database/migrations ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 7.54 KB
dist/collections/endpoints ${{\color{Goldenrod}{ }}}$ 0.4%, 6.23 KB
dist/auth/strategies ${{\color{Goldenrod}{ }}}$ 0.4%, 5.43 KB
dist/queues/config ${{\color{Goldenrod}{ }}}$ 0.4%, 5.31 KB
(other) ${{\color{Goldenrod}{ ███████▉ }}}$ 31.6%, 443.37 KB

Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ███████████████████▉ }}}$ 79.5%, 150.12 KB
dist/fields/validations.js ${{\color{Goldenrod}{ █▍ }}}$ 5.6%, 10.57 KB
dist/config/orderable ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 3.13 KB
dist/fields/baseFields ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 2.79 KB
dist/utilities/deepCopyObject.js ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 2.54 KB
dist/auth/cookies.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.55 KB
dist/utilities/flattenTopLevelFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.42 KB
dist/fields/config ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 1.29 KB
dist/utilities/getVersionsConfig.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 1.04 KB
dist/utilities/flattenAllFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 943 B
dist/utilities/unflatten.js ${{\color{Goldenrod}{ }}}$ 0.4%, 779 B
dist/utilities/sanitizeUserDataForEmail.js ${{\color{Goldenrod}{ }}}$ 0.4%, 713 B
dist/utilities/getFieldPermissions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 651 B
dist/collections/config ${{\color{Goldenrod}{ }}}$ 0.3%, 570 B
dist/bin/generateImportMap ${{\color{Goldenrod}{ }}}$ 0.3%, 561 B
dist/auth/sessions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 525 B
dist/fields/getFieldPaths.js ${{\color{Goldenrod}{ }}}$ 0.3%, 485 B
dist/utilities/appendDateTimezoneSelectFields.js ${{\color{Goldenrod}{ }}}$ 0.2%, 451 B
dist/utilities/getSafeRedirect.js ${{\color{Goldenrod}{ }}}$ 0.2%, 423 B
dist/utilities/deepMerge.js ${{\color{Goldenrod}{ }}}$ 0.2%, 413 B
(other) ${{\color{Goldenrod}{ █████▏ }}}$ 20.5%, 38.61 KB

Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
dist/features/blocks ${{\color{Goldenrod}{ ███ }}}$ 12.4%, 37.36 KB
dist/lexical/ui ${{\color{Goldenrod}{ ██▊ }}}$ 11.4%, 34.16 KB
dist/lexical/plugins ${{\color{Goldenrod}{ ██▋ }}}$ 10.9%, 32.88 KB
dist/features/experimental_table ${{\color{Goldenrod}{ ██▎ }}}$ 9.0%, 27.16 KB
dist/packages/@lexical ${{\color{Goldenrod}{ █▌ }}}$ 6.3%, 18.99 KB
dist/features/link ${{\color{Goldenrod}{ █▌ }}}$ 6.3%, 18.81 KB
dist/features/toolbars ${{\color{Goldenrod}{ █▍ }}}$ 5.5%, 16.58 KB
dist/features/upload ${{\color{Goldenrod}{ █▏ }}}$ 4.7%, 14.09 KB
dist/features/textState ${{\color{Goldenrod}{ ▉ }}}$ 3.7%, 11.08 KB
dist/features/relationship ${{\color{Goldenrod}{ ▊ }}}$ 3.1%, 9.39 KB
dist/lexical/utils ${{\color{Goldenrod}{ ▋ }}}$ 2.9%, 8.79 KB
dist/features/converters ${{\color{Goldenrod}{ ▋ }}}$ 2.8%, 8.36 KB
dist/features/debug ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 7.40 KB
dist/utilities/fieldsDrawer ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 7.29 KB
dist/lexical/config ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 5.08 KB
dist/features/lists ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 5.00 KB
dist/features/format ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 3.46 KB
dist/lexical/LexicalEditor.js ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.23 KB
dist/features/horizontalRule ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.18 KB
dist/field/Field.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.84 KB
(other) ${{\color{Goldenrod}{ █████████████████████▉ }}}$ 87.6%, 263.53 KB

Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ███████████▋ }}}$ 46.8%, 579.57 KB
dist/elements/Hierarchy ${{\color{Goldenrod}{ ▉ }}}$ 3.5%, 43.65 KB
dist/elements/BulkUpload ${{\color{Goldenrod}{ ▌ }}}$ 2.3%, 28.06 KB
dist/views/HierarchyList ${{\color{Goldenrod}{ ▍ }}}$ 1.6%, 19.26 KB
dist/elements/Table ${{\color{Goldenrod}{ ▍ }}}$ 1.6%, 19.25 KB
dist/views/Edit ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 17.28 KB
dist/elements/WhereBuilder ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 17.28 KB
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.87 KB
dist/fields/Relationship ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 15.48 KB
dist/fields/Blocks ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 15.12 KB
dist/fields/Upload ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 14.39 KB
dist/elements/QueryPresets ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.25 KB
dist/elements/PublishButton ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 9.01 KB
dist/elements/HTMLDiff ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.38 KB
dist/elements/LivePreview ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.21 KB
dist/views/List ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.97 KB
dist/elements/ReactSelect ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.84 KB
dist/fields/Array ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.76 KB
dist/elements/RelationshipTable ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.88 KB
dist/elements/Upload ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.61 KB
(other) ${{\color{Goldenrod}{ █████████████▎ }}}$ 53.2%, 659.92 KB

Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js

Path Size
dist/graphics/Logo ${{\color{Goldenrod}{ ███████▊ }}}$ 31.1%, 5.57 KB
../../node_modules ${{\color{Goldenrod}{ ███▋ }}}$ 14.8%, 2.65 KB
dist/graphics/Icon ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 1.52 KB
dist/utilities/formatDocTitle ${{\color{Goldenrod}{ █▊ }}}$ 7.4%, 1.32 KB
dist/providers/TableColumns ${{\color{Goldenrod}{ █▏ }}}$ 4.8%, 866 B
dist/utilities/getGlobalData.js ${{\color{Goldenrod}{ █ }}}$ 4.2%, 762 B
dist/utilities/api.js ${{\color{Goldenrod}{ █ }}}$ 4.2%, 756 B
dist/utilities/groupNavItems.js ${{\color{Goldenrod}{ █ }}}$ 4.1%, 734 B
dist/elements/Translation ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 493 B
dist/utilities/handleTakeOver.js ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 440 B
dist/utilities/traverseForLocalizedFields.js ${{\color{Goldenrod}{ ▌ }}}$ 2.2%, 399 B
dist/elements/withMergedProps ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 339 B
dist/utilities/getNavGroups.js ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 338 B
dist/utilities/getVisibleEntities.js ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 329 B
dist/elements/WithServerSideProps ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 232 B
dist/utilities/handleGoBack.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 180 B
dist/fields/mergeFieldStyles.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 159 B
dist/utilities/handleBackToDashboard.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 152 B
dist/forms/Form ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 147 B
dist/utilities/abortAndIgnore.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 146 B
(other) ${{\color{Goldenrod}{ █████████████████▏ }}}$ 68.9%, 12.36 KB
Details

Next to the size is how much the size has increased or decreased compared with the base branch of this PR.

  • ‼️: Size increased by 20% or more. Special attention should be given to this.
  • ⚠️: Size increased in acceptable range (lower than 20%).
  • ✅: No change or even downsized.
  • 🗑️: The out file is deleted: not found in base branch.
  • 🆕: The out file is newly found: will be added to base branch.

@jacobsfletch jacobsfletch force-pushed the refactor/admin-adapter-types branch from 149a4c4 to 709d8f4 Compare May 27, 2026 19:16
@jacobsfletch jacobsfletch changed the base branch from refactor/admin-adapter-types to feat/admin-router-adapter May 27, 2026 19:20
Adds server-side adapter passed into server functions (not React context),
abstracting framework-specific APIs like cookies, headers, redirect, and
forbidden/unauthorized/notFound boundaries.

- Define ServerAdapter type and Next.js implementation
- Wire ServerAdapter through plugin-multi-tenant entrypoints
- Safely access req.server from optional contexts
@jacobsfletch jacobsfletch force-pushed the refactor/server-adapter-abstraction branch from b9942c4 to c7cdd4f Compare May 27, 2026 19:31
Co-locates the Next ServerAdapter impl with the RouterAdapter impl under
packages/next/src/adapters/. Both are framework bridges, not utilities.
…-abstraction

Adopts the adapters/ folder split for payload core. Resolves the conflict on
admin/adapters.ts by extracting ServerAdapter into adapters/server.ts and
updating the two ServerAdapter consumers (config/types.ts, types/index.ts).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant