feat(c3): scaffold Next.js apps with vinext instead of OpenNext - #14896
feat(c3): scaffold Next.js apps with vinext instead of OpenNext#14896scottbuscemi wants to merge 5 commits into
Conversation
Point create-cloudflare --framework=next at create-vinext-app so the generated project matches the recommended Next.js-on-Workers path (vinext dev/build + vinext-cloudflare deploy) instead of the OpenNext remote template.
🦋 Changeset detectedLatest commit: 920c3f4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Prompt for vinext (default) vs OpenNext when scaffolding Next.js. --variant=vinext|opennext and -y/--accept-defaults (vinext) cover the non-interactive paths so OpenNext stays one flag away.
Update: OpenNext kept as an opt-in variantPer review feedback, C3 no longer drops OpenNext entirely.
Non-interactive: npm create cloudflare@latest my-app -- --framework=next --variant=vinext
npm create cloudflare@latest my-app -- --framework=next --variant=opennextE2E covers both ( |
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
|
Curious if this should also be changed in autoconfig (people deploying existing Next apps)? I've been working on small improvements to Next autoconfig here #14892, but if vinext is the default path, could autconfig run cc @james-elicx keen to hear what you think 🙂 |
In theory it should work most of the time. In practice, you can never be 100% sure as there's always going to be the chance of a dependency or pattern that makes it incompatible. But, that doesn't necessarily mean we shouldn't do it, because those issues would likely also apply to OpenNext apps. |
|
Codeowners approval required for this PR:
Show detailed file reviewers |
|
@scottbuscemi I think this is good as it is, we will need to come back to add docs on prewarming and workers cache once in place, but that's a little way off and this is still a better experience than what you're likely to get out of the box with the alternative. |
# Conflicts: # packages/create-cloudflare/src/frameworks/package.json
workers-devprod
left a comment
There was a problem hiding this comment.
Codeowners reviews satisfied
@cloudflare/autoconfig
@cloudflare/build-output-utils
@cloudflare/config
create-cloudflare
@cloudflare/deploy-helpers
@cloudflare/kv-asset-handler
miniflare
@cloudflare/pages-functions
@cloudflare/pages-shared
@cloudflare/unenv-preset
@cloudflare/vite-plugin
@cloudflare/vitest-pool-workers
@cloudflare/workers-auth
@cloudflare/workers-editor-shared
@cloudflare/workers-utils
wrangler
commit: |
| previewScript: "preview", | ||
| deployScript: "deploy", | ||
| typesPath, | ||
| typesPath: VINEXT_TYPES_PATH, |
There was a problem hiding this comment.
🟡 Extra options typed after the preview command are silently dropped for new Next.js projects
The generated preview command is built by chaining two package-manager invocations (preview: "${npm} run build && ${npm} run start" at packages/create-cloudflare/templates/next/c3.ts:158) without a -- separator, so anything the user appends (for example a port) is swallowed by the package manager instead of reaching the local server.
Impact: People previewing a freshly scaffolded Next.js app cannot pass options such as a custom port; the server silently starts with defaults.
How the chained script swallows forwarded arguments
C3 declares previewScript: "preview" (packages/create-cloudflare/templates/next/c3.ts:164), and the e2e harness invokes it as <pm> run preview [--] <previewArgs> --port <port> (packages/create-cloudflare/e2e/helpers/framework-helpers.ts:286-305). Because the script body is npm run build && npm run start, the shell appends the forwarded arguments to the second command as npm run start --inspector-port=0 --port 1234. Without a --, npm/pnpm treat those as their own config flags and never pass them to wrangler dev, so the preview server binds to the default port and the new e2e test at packages/create-cloudflare/e2e/tests/frameworks/test-config.ts:353-357 will fetch a port nothing is listening on. The OpenNext variant avoids this because its preview script ends in a single command that accepts a ---separated tail.
Prompt for agents
The generated vinext `preview` script in packages/create-cloudflare/templates/next/c3.ts is `"<pm> run build && <pm> run start"`. C3 (and the e2e helper verifyPreviewScript in packages/create-cloudflare/e2e/helpers/framework-helpers.ts) forwards extra CLI arguments (e.g. `--port <n>`, `--inspector-port=0`) to `<pm> run preview -- <args>`, which the shell appends to the trailing `<pm> run start` invocation. Without a `--` separator, npm/pnpm consume those flags as their own config and `wrangler dev` never receives them, so a custom port is ignored. Consider making the preview script forward arguments explicitly (e.g. make the last segment `<pm> run start --` or inline the wrangler dev command so trailing arguments reach it), and update the corresponding e2e previewArgs accordingly.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if (ctx.args.variant === "opennext") { | ||
| return {}; | ||
| } |
There was a problem hiding this comment.
🟡 Initial git commit records the wrong scaffolding tool when the OpenNext option is chosen
The Next.js template always advertises the vinext scaffolding tool (frameworkCli: "create-vinext-app" at packages/create-cloudflare/templates/next/c3.ts:144) even when the OpenNext option is picked, so the automatically created first commit describes a tool that was never run.
Impact: Users who choose OpenNext get a misleading initial commit message about how their project was created.
Where the framework CLI name leaks into the commit message
createCommitMessage in packages/create-cloudflare/src/git.ts:119-135 reads ctx.template.frameworkCli and appends framework cli = ${getFrameworkCli(ctx)}, which resolves to create-vinext-app@1.0.0-beta.1 from packages/create-cloudflare/src/frameworks/package.json. The OpenNext path never invokes any framework CLI — it downloads a remote template via downloadRemoteTemplate (packages/create-cloudflare/templates/next/c3.ts:98-108) — so the recorded CLI (and version) is fabricated for that variant.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Makes
create-cloudflare --framework=nextconfigure vinext, while keeping opennext available with a flag.Today C3's Next template only downloads the OpenNext remote template (
github:opennextjs/opennextjs-cloudflare/create-cloudflare/next). The docs PR at cloudflare/cloudflare-docs#31887 recommends vinext as the default. This PR makes C3 do the same, with OpenNext retained as an opt-in variant.Behavior
Interactive (
--framework=next) prompts:Non-interactive:
-y/--accept-defaultsselects vinext.Changes
templates/next/c3.ts(and experimental re-export):--variantforvinext|opennextcreate-vinext-appviarunFrameworkGeneratorwith--platform cloudflare --data-cache none --yes --skip-install --disable-git+ matching package-manager flagpreviewscript (build && start) so C3's sharedpreviewScript: "preview"works for both variantscreate-vinext-app@1.0.0-beta.1insrc/frameworks/package.json(keepcreate-next-apppin as well)next(vinext) +next:opennextin both stable and experimental matrices;getFrameworkConfigtolerates non-platform labels likenext:opennextGenerated project shapes
vinext (default)
{ "scripts": { "dev": "vinext dev", "build": "vinext build", "start": "wrangler dev --config dist/server/wrangler.json", "preview": "<pm> run build && <pm> run start", "deploy": "vinext-cloudflare deploy --config dist/server/wrangler.json" } }opennext — same as today's template (
opennextjs-cloudflare build/deploy/preview, etc.)Notes / follow-ups for reviewers
--variant=opennextand the manual OpenNext adapter docs.--data-cache noneon the vinext path avoids a placeholder KV namespace id that would block deploy until the user provisions one.Note
This is a contribution from an AI agent: opencode, xai/grok-4.5. Opened as a draft for human review before any merge consideration.