Link to the code that reproduces this issue
https://github.com/jantimon/repro-turbopack-swc-plugin-environment
To Reproduce
- Clone the repo (contains a minimal SWC plugin that reads TransformPluginMetadataContextKind::Env and replaces ENV_CHECK with the value)
- Build the SWC plugin: cd swc-plugin-env-check && cargo build --target wasm32-wasip1 --release && cd ..
- npm install
- Run next build (uses turbopack by default in Next 16)
- Check the output: grep -o 'strong>[^<]*</strong' .next/server/app/index.html
- You'll see development instead of production
- Compare with next build --webpack which correctly outputs production
Current vs. Expected behavior
Current: next build --turbopack passes "development" as the env to SWC plugins via TransformPluginMetadataContextKind::Env, regardless of whether it's a dev or prod build.
Expected: next build --turbopack should pass "production", same as webpack does.
| Mode |
Bundler |
Env received |
Correct? |
| Dev |
Turbopack |
"development" |
Yes |
| Dev |
Webpack |
"development" |
Yes |
| Prod |
Webpack |
"production" |
Yes |
| Prod |
Turbopack |
"development"* |
No |
The root cause looks like a hardcoded "development" in turbopack:
|
//[TODO]: Support env-related variable injection, i.e process.env.NODE_ENV |
|
"development".to_string(), |
//[TODO]: Support env-related variable injection, i.e process.env.NODE_ENV
"development".to_string(),
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.3.0
Binaries:
Node: 24.13.0
npm: 11.6.2
Yarn: 1.22.22
pnpm: 10.17.1
Relevant Packages:
next: 16.2.1-canary.28
eslint-config-next: N/A
react: 19.2.5
react-dom: 19.2.5
typescript: 6.0.2
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Turbopack, SWC
Which stage(s) are affected? (Select all that apply)
next build (local)
Additional context
Tested on both 16.2.3 (stable) and 16.2.1-canary.28 (latest canary) — same behavior.
We hit this migrating galaxus.ch to turbopack. Our translation SWC plugin uses the env to split imports per-key in prod vs bundling all translations in dev. With turbopack always reporting dev, prod builds ship the full dictionary +1.4 MB JS transferred.
Link to the code that reproduces this issue
https://github.com/jantimon/repro-turbopack-swc-plugin-environment
To Reproduce
Current vs. Expected behavior
Current: next build --turbopack passes "development" as the env to SWC plugins via TransformPluginMetadataContextKind::Env, regardless of whether it's a dev or prod build.
Expected: next build --turbopack should pass "production", same as webpack does.
The root cause looks like a hardcoded "development" in turbopack:
next.js/turbopack/crates/turbopack-ecmascript-plugins/src/transform/swc_ecma_transform_plugins.rs
Lines 240 to 241 in b5da7b7
Provide environment information
Which area(s) are affected? (Select all that apply)
Turbopack, SWC
Which stage(s) are affected? (Select all that apply)
next build (local)
Additional context
Tested on both 16.2.3 (stable) and 16.2.1-canary.28 (latest canary) — same behavior.
We hit this migrating galaxus.ch to turbopack. Our translation SWC plugin uses the env to split imports per-key in prod vs bundling all translations in dev. With turbopack always reporting dev, prod builds ship the full dictionary +1.4 MB JS transferred.