payloadcms / payloadcms/payload
loadEnv fails with "Cannot destructure property 'loadEnvConfig'" on Next.js 15.5+
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 44.8k
- Forks
- 4.2k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 53
Description
loadEnv fails with Cannot destructure property 'loadEnvConfig' of 'import_env.default' as it is undefined on Next.js 15.5+
Summary
payload/dist/bin/loadEnv.js does import nextEnvImport from '@next/env' and then destructures loadEnvConfig from it. On Next.js 15.5+ the @next/env package no longer exposes a default export — only named exports remain — so nextEnvImport is undefined when the module is loaded through certain interop paths, and the destructure throws.
This affects any tooling that imports payload/node (which re-exports loadEnv from bin/loadEnv.js), including running custom scripts that import payload.config via tsx.
Reproduction
payload@3.84.1@payloadcms/db-vercel-postgres@3.84.1(which transitively importspayload/nodevia@payloadcms/drizzle/utilities/blocksToJsonMigrator)next@15.5.18(pins@next/env@15.5.18)tsx@4.21.0- Node.js v22.14
A script that does:
import { getPayload } from "payload";
import config from "../payload.config";
const payload = await getPayload({ config });
run via yarn dotenv -e .env.local -- tsx scripts/foo.ts produces:
TypeError: Cannot destructure property 'loadEnvConfig' of 'import_env.default' as it is undefined.
at loadedEnvFiles (node_modules/payload/dist/bin/loadEnv.js:3:9)
Root cause
node_modules/@next/env/dist/index.js is a webpack-bundled CJS file whose module.exports is { initialEnv, updateInitialEnv, processEnv, resetEnv, loadEnvConfig } — there is no default property.
Verification:
node -e "console.log(require('@next/env').default)"
# => undefined
node -e "import('@next/env').then(m => console.log(typeof m.default, Object.keys(m)))"
# => object [ initialEnv, updateInitialEnv, processEnv, resetEnv, loadEnvConfig ]
Older Next.js (pre-15.5) exposed module.exports.default = ... for legacy default-import compatibility, so the existing Payload code happened to work. PR #7047 fixed an earlier instance of this on a different path, but the same anti-pattern remains in bin/loadEnv.js.
Proposed fix
-import nextEnvImport from '@next/env';
+import * as nextEnvImport from '@next/env';
import { findUpSync } from '../utilities/findUp.js';
-const { loadEnvConfig } = nextEnvImport;
+const { loadEnvConfig } = nextEnvImport.default ?? nextEnvImport;
The ?? nextEnvImport fallback keeps backwards-compat with Next.js < 15.5 (where default is the namespace object), while supporting 15.5+ (where named exports live on the namespace itself).
I have this applied locally via patch-package and it resolves the error.
Environment
| Package | Version |
|---|---|
payload |
3.84.1 |
@payloadcms/next |
3.84.1 |
@payloadcms/db-vercel-postgres |
3.84.1 |
next |
15.5.18 |
@next/env |
15.5.18 |
tsx |
4.21.0 |
| Node.js | 22.14.0 |
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the failure with payload 3.84.1, Next.js 15.5.18, and the listed tsx script, then inspect payload/dist/bin/loadEnv.js and its source counterpart. Verify how @next/env is imported across the supported Next.js versions. Done means importing payload/node no longer throws and loadEnvConfig remains compatible with older and newer @next/env exports.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- next.js, typescript
- Domain
- backend, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100