npm init builder.io@latest scaffold is broken on Next.js 16: stale Turbopack detection injects a webpack-only DevTools config
- Dominant language
- TypeScript
- Stars
- 8.8k
- Forks
- 1.2k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 17
Description
> **Tracker note:** The fix for this does **not** live in `BuilderIO/builder`. It belongs to the
> separately-published `create-builder.io` and `@builder.io/dev-tools` packages, neither of which
> declares a `repository` or `bugs` URL on npm (both only list `homepage: https://builder.io/`).
> Filing here as the closest public Builder tracker so it isn't lost — please move it if there's a
> better internal home.
## Summary
`npm init builder.io@latest` → "Next.js" produces a project that **cannot start** on Next.js 16.
```
⨯ ERROR: This build is using Turbopack, with a `webpack` config and no `turbopack` config.
This may be a mistake.
As of Next.js 16 Turbopack is enabled by default and
custom webpack configurations may need to be migrated to Turbopack.
```
This is a hard error, not a warning: `next dev` never serves a page, and `next build` fails with
`Error: Call retries were exceeded`. It affects **every new user** running the quickstart now that
`create-next-app` resolves to Next 16.
Reproduced verbatim against a clean Next.js 16.2.12 scaffold with `create-builder.io@1.0.29` and
`@builder.io/dev-tools@1.78.0`.
## Root cause
The CLI's Turbopack guard tests for the literal string `--turbopack` in `package.json` →
`scripts.dev`. From the published `create-builder.io@1.0.29` bundle:
```js
// Turbopack detection
async function qu(t) {
let i = await Oi(t, t.getRepoRootDir());
return i?.scripts?.dev ? i.scripts.dev.includes("--turbopack") : false;
}
// used by the Next.js config injector
if (await qu(t)) return console.warn(
"Turbopack does not support the Builder.io devtools cli. Please disable Turbopack " +
"or manually integrate Builder.io into your Next.js project."
), n;
```
Next.js 15's `create-next-app` emitted `"dev": "next dev --turbopack"`, so the guard worked.
**Next.js 16 made Turbopack the default and dropped the flag** — the generated script is now
plain `"dev": "next dev"`. The check returns `false`, the guard fails open, and the CLI proceeds
to inject `BuilderDevTools()` from `@builder.io/dev-tools/next` into `next.config.ts`.
That plugin adds a webpack-only key unconditionally
(`node_modules/@builder.io/dev-tools/next/index.mjs`, v1.78.0):
```js
export default (opts = {}) => (nextConfig = {}) =>
Object.assign({}, nextConfig, {
webpack(config, options) {
if (opts.enabled !== false) config.plugins.push(new BuilderDevToolsPlugin(opts));
if (typeof nextConfig.webpack === "function") return nextConfig.webpack(config, options);
return config;
},
});
```
Next 16 sees a `webpack` config with no `turbopack` config → hard error.
### Failure chain
```mermaid
flowchart TD
A["npm init builder.io@latest"] --> B["create-builder.io@1.0.29"]
B --> C["npx create-next-app builder-app
(unpinned → Next 16.2.12)"]
C --> D["scripts.dev = 'next dev'
NO --turbopack flag"]
D --> E{"guard: scripts.dev.includes('--turbopack')"}
E -->|"false — fails open"| F["inject BuilderDevTools() into next.config.ts"]
F --> G["dev-tools/next adds a 'webpack' key"]
G --> H["Next 16: webpack config + no turbopack config"]
H --> I["HARD ERROR — dev and build both fail"]
E -->|"true (Next 15 only)"| J["warn + skip injection ✅"]
style I fill:#ffcccc
style E fill:#ffe4b5
```
## Issue 2 — DevTools is silently dead under Turbopack
The obvious workaround (`turbopack: {}`) is a trap. Under Turbopack the `webpack()` hook is
**never invoked**, so `BuilderDevToolsPlugin` never registers. The error disappears, the app runs,
and DevTools is inert with no diagnostic.
Measured on the repro app — served HTML scanned for injected assets:
| Config | Turbopack error | Dev server | DevTools overlay |
|---|---|---|---|
| none (as the CLI leaves it) | ❌ hard error | never serves | n/a |
| `turbopack: {}` | ✅ gone | ✅ serves | ❌ **silently absent** |
| `next dev --webpack` | ✅ gone | ✅ serves | ✅ plugin initialises |
With `turbopack: {}`, occurrence counts in the served HTML were `dev-tools -> 0`,
`builder -> 0`, `Builder -> 0`. The only `devtools` hits were Next's own `next-devtools` chunk.
`@builder.io/dev-tools` has no Turbopack support at all — its export map is `core`, `figma`,
`figma/jsx-runtime`, `next`, `node`, `remix`, `remix/server-build`, `server`, `vite`, `webpack`,
`angular`. **No turbopack entry.**
This is what users actually hit in practice: they find `turbopack: {}` via the error message's own
TIP, get a running app, and then report "the DevTools overlay never appears."
## Issue 3 — `/` renders the stock Next.js splash page
Separate from the above, and a real onboarding regression.
The CLI writes `app/[...page]/page.tsx` — a **required** catch-all, which does not match zero
segments — and never touches `app/page.tsx`. So the root URL always falls through to the untouched
`create-next-app` homepage. There is no Builder-branded landing page or "Get Started" button
anywhere in this flow.
Verified by route probe:
```
/ -> catch-all: false | next-splash: true
/some-builder-page -> catch-all: true | next-splash: false
```
The legacy starter used `pages/[[...page]].tsx` — an **optional** catch-all, which *does* match `/`
— so Builder content used to be served at the root. Users following the quickstart reasonably
expect a branded landing page and instead get "To get started, edit page.tsx" with zero Builder
branding, which reads as a failed install.
For the record, API-key wiring is fine and is **not** implicated: the CLI writes
`NEXT_PUBLIC_BUILDER_API_KEY` into `.env.local` (first match of `.env.local`,
`.env.development.local`, `.env.production.local`, `.env.development`, `.env.production`, `.env`)
and consumes it in the generated `builder-page.tsx` — gen1 via
`builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY!)`, gen2 as `apiKey` on ``.
## Issue 4 — `next build --webpack` is separately broken
Even on the `--webpack` path, production builds fail. The plugin loads
(`[builder-dev-tools] webpack setupDevTools init`) and then throws:
```
unhandledRejection Error: createDevTools() requires a TypeScript instance passed to the 'ts' option
```
So `--webpack` rescues `dev` but not `build`.
## Proposed fix
1. **Fix the Turbopack detection.** Gate on the installed Next.js major version, not the
`--turbopack` substring: Next ≥ 16 means Turbopack unless `--webpack` is explicitly passed.
The CLI **already ships a version probe** it doesn't use here — it spawns `npx next -v` and
parses `{ major, minor, patch }`. Reuse it.
2. **Add Turbopack support to `@builder.io/dev-tools`** — the real fix. Until that exists, when
Turbopack is detected the CLI should either skip injection (the existing warning path) or write
`"dev": "next dev --webpack"` into `package.json` alongside the plugin, so the injected config is
actually honoured. Silently injecting a no-op webpack plugin is the worst of the three.
3. **Fix `next build --webpack`** — pass the TypeScript instance so `createDevTools()` stops throwing.
4. **Pin `create-next-app`** to a known-good major. It is currently invoked unpinned
(`npx create-next-app builder-app`), so the CLI inherits every future Next.js breaking change on
the day it ships.
5. **Reconsider `[...page]` vs `[[...page]]`.** The optional catch-all restores Builder content at
`/` and matches the legacy starter, though it would overwrite the create-next-app homepage. At
minimum, print a next step telling users which URL to visit.
### Underlying anti-pattern
Gating behaviour on a CLI **flag string** rather than the framework version is what broke here, and
it will break again on the next default flip. Worth fixing as a pattern, not just this instance.
## Workaround for users today
1. Use `"dev": "next dev --webpack"` — **not** `turbopack: {}` alone, or DevTools stays silently
disabled.
2. Visit a non-root path such as `/test`; `/` will always show the Next.js splash page.
3. Create a page at that URL in the Builder space matching `NEXT_PUBLIC_BUILDER_API_KEY` in
`.env.local`.
## Environment
| | |
|---|---|
| `create-builder.io` | 1.0.29 |
| `@builder.io/dev-tools` | 1.78.0 |
| `next` | 16.2.12 |
| `react` / `react-dom` | 19.2.4 |
| Repro | `npx create-next-app@latest --ts --app`, then the CLI's `next.config.ts` transform |
## Side note for maintainers (recommendation only — no action taken)
While tracing this, `packages/create-builder.io` in `BuilderIO/builder` was confirmed to be **dead
code**. It is version `0.1.4`, whereas npm serves `create-builder.io@1.0.29` from a different
codebase. The published bundle contains **zero** references to `starters/create-builder`,
`BuilderIO/builder`, or `archive/main.zip`, so neither the in-repo CLI nor the `starters/` tree is
reachable from the public quickstart.
This actively misdirects investigation — `packages/create-builder.io` and
`starters/create-builder/nextjs` are the first things anyone greps for, and both look plausible
while being unreachable. Recommend deprecating or removing them, **pending maintainer sign-off**.
Also note `starters/` is listed in `.prettierignore`, which causes some tooling to skip that tree
entirely; a raw filesystem scan is needed to audit it.
For completeness, no template in `BuilderIO/builder` has this bug. Only three `next.config.*` files
contain a `webpack` block and all are pinned below Next 16, so none need a `turbopack` key:
| File | Next | webpack block |
|---|---|---|
| `examples/next-js-builder-site/next.config.js` | 12.3.5 | Preact aliasing |
| `packages/react-tests/next14-pages/next.config.js` | 14.2.25 | react alias |
| `packages/sdks/snippets/gen1-next-14/next.config.js` | 14.2.25 | react alias |
Contributor guide
No contributing guide indexed for this repository
Research direction
Reproduce the quickstart with `create-builder.io@1.0.29`, Next.js 16.2.12, and `@builder.io/dev-tools@1.78.0`; inspect the published CLI's Turbopack guard and `@builder.io/dev-tools/next/index.mjs`. Check `next dev`, `next build`, and the generated `app/[...page]/page.tsx`; done requires an agreed scope and validated behavior for the dev server, production build, and root route.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- next.js, react, typescript
- Domain
- cli, frontend, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100