payloadcms/payload · error · Error

Could not find ExportDefaultDeclaration in next.config.js

Error message

Could not find ExportDefaultDeclaration in next.config.js

What it means

While parsing an ESM next.config.js, esprima-next found neither an ExportDefaultDeclaration nor an ExportNamedDeclaration in the AST body, so there is no export to wrap with withPayload. The message names only ExportDefaultDeclaration but the guard also covers named exports.

Source

Thrown at packages/create-payload-app/src/lib/wrap-next-config.ts:85

          )
          return { modifiedConfigContent, success: true }
        }

        return Promise.resolve({
          modifiedConfigContent: content,
          success: false,
        })
      } else if (configType === 'esm') {
        const exportDefaultDeclaration = ast.body.find(
          (p) => p.type === Syntax.ExportDefaultDeclaration,
        ) as Directive | undefined

        const exportNamedDeclaration = ast.body.find(
          (p) => p.type === Syntax.ExportNamedDeclaration,
        ) as ExportNamedDeclaration | undefined

        if (!exportDefaultDeclaration && !exportNamedDeclaration) {
          throw new Error('Could not find ExportDefaultDeclaration in next.config.js')
        }

        if (exportDefaultDeclaration && exportDefaultDeclaration.declaration?.loc) {
          const modifiedConfigContent = insertBeforeAndAfter(
            content,
            exportDefaultDeclaration.declaration.loc,
          )
          return { modifiedConfigContent, success: true }
        } else if (exportNamedDeclaration) {
          const exportSpecifier = exportNamedDeclaration.specifiers.find(
            (s) =>
              s.type === 'ExportSpecifier' &&
              s.exported?.name === 'default' &&
              s.local?.type === 'Identifier' &&
              s.local?.name,
          )

          if (exportSpecifier) {

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Open next.config.js and ensure it has `export default { ... }` (ESM) so withPayload can wrap it.
  2. If the project actually uses CommonJS, ensure the file/extension detection picks the cjs path (rename to next.config.cjs or set type accordingly).
  3. As a fallback, follow the printed instructions to manually wrap the config with withPayload.
  4. Run the CLI on a clean, standard Next.js config first to confirm, then port your customizations.

Example fix

// before — next.config.js with no export
console.log('config loading')

// after
import { withPayload } from '@payloadcms/next/withPayload'

const nextConfig = {
  // your config
}

export default withPayload(nextConfig)
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'fs'

function assertNextConfigHasExport(configPath: string) {
  const src = fs.readFileSync(configPath, 'utf8')
  if (!/export\s+default\b/.test(src) && !/export\s+\{/.test(src)) {
    throw new Error(`${configPath} has no export default or named export — cannot wrap with withPayload`)
  }
}

Try / catch

try {
  await wrapNextConfig({ nextConfigPath, nextConfigType: 'esm' })
} catch (e) {
  if (e instanceof Error && e.message.includes('ExportDefaultDeclaration')) {
    console.error('Manually wrap your next.config.js export with withPayload (see printed instructions).')
  }
  throw e
}

Prevention

When it happens

Trigger: create-payload-app init/upgrade on a Next.js project whose next.config.js (detected as ESM) has no export default or export statement — e.g. a config file that only assigns globals, re-exports via dynamic import, or was left as a stub.

Common situations: A next.config.js that exports nothing (side-effect only); a config already using a non-standard pattern; accidental CJS syntax in a .js file treated as ESM; a manually emptied config.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/284b53cfbc84cad8. Report an issue: GitHub.