Skip to content

feat(c3): scaffold Next.js apps with vinext instead of OpenNext - #14896

Open
scottbuscemi wants to merge 5 commits into
cloudflare:mainfrom
scottbuscemi:c3-next-use-vinext
Open

feat(c3): scaffold Next.js apps with vinext instead of OpenNext#14896
scottbuscemi wants to merge 5 commits into
cloudflare:mainfrom
scottbuscemi:c3-next-use-vinext

Conversation

@scottbuscemi

@scottbuscemi scottbuscemi commented Jul 28, 2026

Copy link
Copy Markdown

Summary

Makes create-cloudflare --framework=next configure 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:

  1. vinext (recommended) — default
  2. OpenNext adapter — previous path

Non-interactive:

npm create cloudflare@latest my-app -- --framework=next --variant=vinext
npm create cloudflare@latest my-app -- --framework=next --variant=opennext

-y / --accept-defaults selects vinext.

Changes

  • templates/next/c3.ts (and experimental re-export):
    • Prompt / --variant for vinext | opennext
    • vinextcreate-vinext-app via runFrameworkGenerator with --platform cloudflare --data-cache none --yes --skip-install --disable-git + matching package-manager flag
    • opennext → existing OpenNext remote template (unchanged)
    • vinext gets a generated preview script (build && start) so C3's shared previewScript: "preview" works for both variants
  • Pin create-vinext-app@1.0.0-beta.1 in src/frameworks/package.json (keep create-next-app pin as well)
  • E2E: next (vinext) + next:opennext in both stable and experimental matrices; getFrameworkConfig tolerates non-platform labels like next:opennext
  • Changeset included

Generated 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


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.

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-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 920c3f4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
create-cloudflare Minor

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.
@scottbuscemi

Copy link
Copy Markdown
Author

Update: OpenNext kept as an opt-in variant

Per review feedback, C3 no longer drops OpenNext entirely. --framework=next now prompts:

  1. vinext (recommended) — default; also selected by -y / --accept-defaults
  2. OpenNext adapter — previous remote-template path

Non-interactive:

npm create cloudflare@latest my-app -- --framework=next --variant=vinext
npm create cloudflare@latest my-app -- --framework=next --variant=opennext

E2E covers both (next and next:opennext). Docs can now truthfully say OpenNext remains available via --variant=opennext (in addition to the manual adapter guide).

@scottbuscemi
scottbuscemi marked this pull request as ready for review July 28, 2026 20:23
@workers-devprod

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/c3-next-vinext.md: [@cloudflare/wrangler]
  • packages/create-cloudflare/e2e/helpers/framework-helpers.ts: [@cloudflare/wrangler]
  • packages/create-cloudflare/e2e/tests/frameworks/frameworks.test.ts: [@cloudflare/wrangler]
  • packages/create-cloudflare/e2e/tests/frameworks/test-config.ts: [@cloudflare/wrangler]
  • packages/create-cloudflare/src/frameworks/package.json: [@cloudflare/wrangler]
  • packages/create-cloudflare/templates/next/c3.ts: [@cloudflare/wrangler]
  • packages/create-cloudflare/templates/next/experimental_c3.ts: [@cloudflare/wrangler]

devin-ai-integration[bot]

This comment was marked as resolved.

@ajhawkings

Copy link
Copy Markdown
Member

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 vinext init rather than opennext migrate? I wonder if that works automatically most of the time (and can handle multiple Next versions), or if agents + skill are often needed to migrate?

cc @james-elicx keen to hear what you think 🙂

@james-elicx

Copy link
Copy Markdown
Member

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 vinext init rather than opennext migrate? I wonder if that works automatically most of the time (and can handle multiple Next versions), or if agents + skill are often needed to migrate?

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.

@workers-devprod

workers-devprod commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

@MattieTK

MattieTK commented Aug 4, 2026

Copy link
Copy Markdown
Member

@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 workers-devprod left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codeowners reviews satisfied

@github-project-automation github-project-automation Bot moved this from Untriaged to Approved in workers-sdk Aug 4, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 4, 2026

Copy link
Copy Markdown
@cloudflare/autoconfig

npm i https://pkg.pr.new/@cloudflare/autoconfig@14896

@cloudflare/build-output-utils

npm i https://pkg.pr.new/@cloudflare/build-output-utils@14896

@cloudflare/config

npm i https://pkg.pr.new/@cloudflare/config@14896

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@14896

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/@cloudflare/deploy-helpers@14896

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@14896

miniflare

npm i https://pkg.pr.new/miniflare@14896

@cloudflare/pages-functions

npm i https://pkg.pr.new/@cloudflare/pages-functions@14896

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@14896

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@14896

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@14896

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@14896

@cloudflare/workers-auth

npm i https://pkg.pr.new/@cloudflare/workers-auth@14896

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@14896

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@14896

wrangler

npm i https://pkg.pr.new/wrangler@14896

commit: 920c3f4

devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

previewScript: "preview",
deployScript: "deploy",
typesPath,
typesPath: VINEXT_TYPES_PATH,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +142 to +144
if (ctx.args.variant === "opennext") {
return {};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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

Labels

None yet

Projects

Status: Approved

Development

Successfully merging this pull request may close these issues.

5 participants