Skip to content

fix(templates): make with-cloudflare-d1 build with published npm packages#17393

Open
SybyAbraham wants to merge 1 commit into
payloadcms:mainfrom
SybyAbraham:fix/cloudflare-d1-template-published-packages
Open

fix(templates): make with-cloudflare-d1 build with published npm packages#17393
SybyAbraham wants to merge 1 commit into
payloadcms:mainfrom
SybyAbraham:fix/cloudflare-d1-template-published-packages

Conversation

@SybyAbraham

@SybyAbraham SybyAbraham commented Jul 17, 2026

Copy link
Copy Markdown

Problem

The with-cloudflare-d1 template on main references several APIs that have not been published to npm. Anyone installing the template via create-payload-app gets TypeScript errors and a failed build.

The root cause: the template is developed inside the monorepo where workspace packages have unreleased APIs. The CI (post-release-templates.yml) only bumps lockfiles — it never runs a standalone build — so these breakages go undetected.

Changes

1. payload buildnext build (package.json)

payload build is not available in any published payload CLI version. Changed the build script to next build.

2. Config.storageConfig.plugins (payload.config.ts)

storage is an unreleased API not in any published @payloadcms/* package. Changed to plugins, which has always existed. (A codemod migrate-storage-adapters-to-config exists upstream for this transition.)

This is the same fix proposed in #17217 and reported in #17195 — this PR includes it as part of a broader fix for the template.

3. generatePayloadViewportmetadata (layout.tsx)

generatePayloadViewport is an unreleased export not in any published @payloadcms/next version. Changed to metadata, which has always been exported. (A codemod migrate-next-generate-viewport-export exists upstream.)

4. CSS/SCSS type declarations (src/assets.d.ts — new)

The monorepo provides declare module '*.css' and declare module '*.scss' via tools/assets.d.ts (wired through tsconfig.base.json). Standalone templates lack this file, causing TS2882 on side-effect style imports. Added src/assets.d.ts with the same declarations.

5. isCLI detection for next build (payload.config.ts)

Switching from payload build to next build means payload/bin.js is no longer in process.argv, so isCLI was always false during build. This caused the config to use getCloudflareContext() (production path requiring CLOUDFLARE_API_TOKEN) instead of getCloudflareContextFromWrangler() (local wrangler path). Extended isCLI to also detect next/dist/bin/next.

6. realpath crash guard (payload.config.ts)

The realpath() helper returned undefined when fs.existsSync() is false — the case for every process.argv entry in the Workers runtime — and the subsequent .endsWith() call on undefined threw. Wrapped in try/catch with a null guard. (Supersedes #17392 for this file.)

7. remoteBindings during build (payload.config.ts, wrangler.jsonc)

getCloudflareContextFromWrangler() was called with remoteBindings: isProduction, which during next build (NODE_ENV=production) tried to connect to real Cloudflare D1/R2 resources. Since this function is only called for CLI/build/dev (never production runtime), changed to remoteBindings: false. Also changed the D1 binding in wrangler.jsonc from remote: true to remote: false so the template builds out of the box without pre-configured Cloudflare resources.

8. engines.node (package.json)

Lowered from >=24.15.0 to >=22.0.0 for compatibility with Cloudflare Workers Builds (Node 22.16.0).

9. Dependency bumps (package.json)

Bumped @payloadcms/* packages from 3.82.1 to 3.86.0 (latest published).

Verification

Cloned the template standalone, applied all changes, ran pnpm install && pnpm run build:

✓ Compiled successfully
✓ Generating static pages (7/7)

Route (app)                                 Size  First Load JS
┌ ƒ /                                    5.47 kB         107 kB
├ ○ /_not-found                             1 kB         103 kB
├ ƒ /admin/[[...segments]]                 393 B         574 kB
├ ƒ /api/[...slug]                         176 B         102 kB
├ ƒ /api/graphql                           133 B         102 kB
├ ƒ /api/graphql-playground                176 B         102 kB
└ ƒ /my-route                              133 B         102 kB

TypeScript compilation passes, all 7 routes generate successfully, no errors.

Relationship to existing issues and PRs

Notes

  • Users who want to use a remote D1 database during development should set remote: true in wrangler.jsonc and provide a real database_id.

…ages

The with-cloudflare-d1 template on main references several APIs that
have not been published to npm, making it impossible to build when
installed standalone via create-payload-app:

1. payload build (build script) - not available in any published
   payload CLI version. Changed to next build.

2. Config.storage (payload.config.ts) - unreleased API not in any
   published @payloadcms/* package. Changed to plugins, which has
   always existed. (A codemod migrate-storage-adapters-to-config
   exists upstream for this transition.)

3. generatePayloadViewport (layout.tsx) - unreleased export not in any
   published @payloadcms/next version. Changed to metadata, which has
   always been exported. (A codemod migrate-next-generate-viewport-export
   exists upstream.)

4. Missing CSS/SCSS type declarations - the monorepo provides these via
   tools/assets.d.ts (wired through tsconfig.base.json), but standalone
   templates lack this file. Added src/assets.d.ts with the same
   declarations.

5. isCLI detection - switching from payload build to next build means
   payload/bin.js is no longer in process.argv, so isCLI was always
   false during build. This caused the config to use
   getCloudflareContext() (production path requiring CLOUDFLARE_API_TOKEN)
   instead of getCloudflareContextFromWrangler() (local wrangler path).
   Extended isCLI to also detect next/dist/bin/next.

6. realpath crash - the realpath() helper returned undefined when
   fs.existsSync() is false (the case for every process.argv entry in
   the Workers runtime), and the subsequent .endsWith() call on
   undefined threw. Wrapped in try/catch with a null guard.

7. remoteBindings during build - getCloudflareContextFromWrangler() was
   called with remoteBindings: isProduction, which during next build
   (NODE_ENV=production) tried to connect to real Cloudflare D1/R2
   resources. Since this function is only called for CLI/build/dev (never
   production runtime), changed to remoteBindings: false. Also changed
   the D1 binding in wrangler.jsonc from remote: true to remote: false
   so the template builds out of the box without pre-configured
   Cloudflare resources.

8. engines.node - lowered from >=24.15.0 to >=22.0.0 for compatibility
   with Cloudflare Workers Builds (Node 22.16.0).

Bumped @payloadcms/* dependencies from 3.82.1 to 3.86.0 (latest
published). Verified with a clean next build: TypeScript compilation
passes, all 7 routes generate successfully.
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​payloadcms/​storage-r2@​3.82.1 ⏵ 3.86.084 +710069 +1100 +1100
Updated@​payloadcms/​db-d1-sqlite@​3.82.1 ⏵ 3.86.082 +710080100 +1100

View full report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant