Rspack plugin feedback #77800
Replies: 39 comments 81 replies
|
let’s go 🚀 |
Environment
Reproduction procedure
ErrorRspack plugin The error stacktrace |
|
i got it working well but in dev it disconnects from hmr many times over, I don't have logs at hand though, had to revert |
|
Hi, currently, my project is using Next.js v13 with Webpack. Is there any workaround to migrate the bundler to Rspack? Alternatively, do you have any suggestions for a different bundler that works well with Next.js v13? My application is getting larger and feels slower, so I’d appreciate any advice. Thanks! |
|
I've been testing next-rspack with our repo, and one of the issues that comes up is to do with the @sentry/nextjs plugin. This is responsible for uploading sourcemaps to sentry during the build. I double checked that the issue was not just because we are using an older major (7) vs the latest (9), and I see different errors for both. On the latest, 9.11.0, I get this error On 7.114.0, I get this error I have confirmed that removing the withRSPack step removes these errors. Cheers, |
|
In dev mode, when loading a page, I see a warning “Failed to lookup module by ID” for every server action file that the page depends on: (Each of these referenced files has |
|
Hey, I was trying out Rspack with PayloadCMS and when trying to build this error happens: |
|
hello, Thank you for your improvements, but I only see a 1 second difference when I test it. rspack : next: |
|
I am using pages router, output export, and NO custom webpack config My package json has next info |
|
I'm getting this error with mapbox + |
|
Super excited by this. In our repo, we already use Rsbuild for non-Next.js applications. Is there a simple way to reuse its config without having to build a second config for Rspack? One middle-ground could be to use e.g. DEBUG mode to spit out the generated Rspack config. My concern is around possible breaking changes in minor versions as this wouldn't be a documented thing |
|
Is Yarn PNP currently not supported?
|
|
Generating a manifest file with manifest.ts throws the following error: Import trace for requested module:
next-metadata-route-loader?filePath=%2FUsers%2Fusername%2FCode%2Facme%2Fproject-name%2Fapps%2Fapp-name%2Fsrc%2Fapp%2Fmanifest.ts&isDynamicRouteExtension=1!?__next_metadata_route__
⨯ next-metadata-route-loader?filePath=%2FUsers%2Fusername%2FCode%2Facme%2Fproject-name%2Fapps%2Fapp-name%2Fsrc%2Fapp%2Fmanifest.ts&isDynamicRouteExtension=1!?__next_metadata_route__
× Module build failed:
╰─▶ × TypeError: context.loadModule is not a function
│ at mod (/Users/username/Code/acme/project-name/node_modules/.pnpm/next@15.3.1-canary.11_@opentelemetry+api@1.9.0_@playwright+test@1.50.1_babel-plugin-react-com_dcec2llys6a7epps6btzp2zqra/node_modules/next/dist/build/webpack/loaders/utils.js:76:17)
│ at new Promise (<anonymous>)
│ at getLoaderModuleNamedExports (/Users/username/Code/acme/project-name/node_modules/.pnpm/next@15.3.1-canary.11_@opentelemetry+api@1.9.0_@playwright+test@1.50.1_babel-plugin-react-com_dcec2llys6a7epps6btzp2zqra/node_modules/next/dist/build/webpack/loaders/utils.js:75:23)
│ at createReExportsCode (/Users/username/Code/acme/project-name/node_modules/.pnpm/next@15.3.1-canary.11_@opentelemetry+api@1.9.0_@playwright+test@1.50.1_babel-plugin-react-com_dcec2llys6a7epps6btzp2zqra/node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js:40:70)
│ at getDynamicTextRouteCode (/Users/username/Code/acme/project-name/node_modules/.pnpm/next@15.3.1-canary.11_@opentelemetry+api@1.9.0_@playwright+test@1.50.1_babel-plugin-react-com_dcec2llys6a7epps6btzp2zqra/node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js:122:9)
│ at Object.nextMetadataRouterLoader (/Users/username/Code/acme/project-name/node_modules/.pnpm/next@15.3.1-canary.11_@opentelemetry+api@1.9.0_@playwright+test@1.50.1_babel-plugin-react-com_dcec2llys6a7epps6btzp2zqra/node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js:256:26)
│ at LOADER_EXECUTION (/Users/username/Code/acme/project-name/node_modules/.pnpm/@rspack+core@1.3.4/node_modules/@rspack/core/dist/index.js:5481:18)
│ at runSyncOrAsync2 (/Users/username/Code/acme/project-name/node_modules/.pnpm/@rspack+core@1.3.4/node_modules/@rspack/core/dist/index.js:5482:6)
│ at node:internal/util:433:21
│ at new Promise (<anonymous>)
│ at runSyncOrAsync2 (node:internal/util:419:12)
│ at isomorphoicRun (/Users/username/Code/acme/project-name/node_modules/.pnpm/@rspack+core@1.3.4/node_modules/@rspack/core/dist/index.js:6270:23)
│ at runLoaders (/Users/username/Code/acme/project-name/node_modules/.pnpm/@rspack+core@1.3.4/node_modules/@rspack/core/dist/index.js:6326:56)
Import trace for requested module:
next-metadata-route-loader?filePath=%2FUsers%2Fusername%2FCode%2Facme%2Fproject-name%2Fapps%2Fapp-name%2Fsrc%2Fapp%2Fmanifest.ts&isDynamicRouteExtension=1!?__next_metadata_route__
GET /manifest.webmanifest 500 in 4826ms |
|
Updated to Works properly on Next 16 beta |
|
Tried rspack with next > tpa-news@0.1.0 dev /home/torten/tpa-news
> next dev
Trace: Cannot call withRspack and pass the --webpack flag.
at console.trace (/home/torten/tpa-news/node_modules/.pnpm/next@15.4.6_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/next/dist/server/node-environment-extensions/console-dev.js:111:32)
at withRspack (/home/torten/tpa-news/node_modules/.pnpm/next-rspack@16.0.0_@swc+helpers@0.5.17/node_modules/next-rspack/index.js:13:13)
at Object.<anonymous> (/home/torten/tpa-news/next.config.compiled.js:42:40)
at Module._compile (node:internal/modules/cjs/loader:1730:14)
at requireFromString (/home/torten/tpa-news/node_modules/.pnpm/next@15.4.6_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/next/dist/build/next-config-ts/require-hook.js:81:7)
at transpileConfig (/home/torten/tpa-news/node_modules/.pnpm/next@15.4.6_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/next/dist/build/next-config-ts/transpile-config.js:98:51)
at async loadConfig (/home/torten/tpa-news/node_modules/.pnpm/next@15.4.6_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/next/dist/server/config.js:1013:36)
at async Module.nextDev (/home/torten/tpa-news/node_modules/.pnpm/next@15.4.6_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/next/dist/cli/next-dev.js:190:14)``` |
|
@next-rspack/core": "1.0.0" didn't work, so I tried the beta version, but I'm getting the following error: Update: The same error occurred with version 1.0.0 (i.e., the latest
|
|
A few issues we spotted while migrating a rather large application:
Just removing the hardcoded
|
|
Issue with 16.0.3 I know the logs say to create an issue in another repo, I am creating it here in case others face the same issue. full command lognext infoI can provide more details if necessary. |
|
Hey everyone! 👋 I've been trying out next-rspack in my Next.js projects and I'm really excited about the build performance benefits! The speed improvements are fantastic, and I'm grateful for all the work the teams are putting into this. I'm currently exploring micro-frontend architectures and was wondering about Module Federation support. I know next-rspack is still experimental, and I'm curious if anyone has insights on: What the future might look like for Rspack feature support in Next.js - particularly around Module Federation? Are there any workarounds or approaches that folks have found helpful for micro-frontends with Next.js in the meantime? How can we best support the development and testing of these experimental features? I completely understand that these integrations take time and careful planning, especially with Next.js's awesome SSR capabilities and routing system. Just excited to learn more about what might be coming down the road! 🚀 Thanks so much for any thoughts or experiences you can share! |
|
In the next16.05 and next-rspack16.05 environment, the UI switches faster than compile is displayed, resulting in a flickering FOUC in the UI. |
|
Updated from Next 16.0.2 to 16.0.6, now CSS import ordering get's messed up every time Fast Refresh rerenders the page. A hard refresh on the browser fixes it, but as soon as I make a code change that triggers Fast Refresh, the CSS is broken again. Initially the css imported in the root layout has the highest precedence. But after a Fast Refresh, css modules are moved up to the top. In my root css I define a |
|
Next 16 + rspack breaks Per maintainer's request:
|
|
next.js and next-rspack v16.0.10 config: error: |
|
While I installed next-rspack@16.1.1, I discovered that the experimental plugin currently has compatibility issues with: |
|
▲ Next.js 16.1.1 (Rspack) If you see error like that : . remove .browserslistrc |
|
our e2e test-suite tests:
we managed to get rspack working although the results are great: ✅ 22 of 23 tests the only failing test is HMR after error recovery - all other bundlers (turbopack,webpack,vite,vite8) manage to update the page after the dev did a syntax error without reloading the page. rspack needs to reload the page here - not sure if that is really an issue but that's the main different I found |
next-rspack vs Turbopack — Bench Report & splitChunks FindingA side-by-side benchmark of Environment (
|
| Metric | rspack | turbopack | Δ |
|---|---|---|---|
| RSS total (MB, post-warmup +30 s) | 6 454 | 13 487 | Turbopack +109 % |
| Process count | 2 | 7 | +5 PostCSS workers |
Turbopack spawns 5 separate PostCSS worker processes (~310–500 MB each) in addition to its main Rust worker; rspack does PostCSS in-process.
DEV — first-hit fetch latency
| Route | rspack (ms) | turbopack (ms) |
|---|---|---|
| Ready | 232 | 153 |
/ (cold cascade) |
15 830 | 13 121 |
/posts |
2 099 | 2 774 |
/notes |
2 228 | 3 942 |
/timeline |
1 670 | 2 476 |
/search |
1 877 | 2 137 |
/friends |
1 998 | 2 443 |
/categories |
2 242 | 3 572 |
/projects |
2 185 | 2 366 |
/says |
2 332 | 2 338 |
/thinking |
2 623 | 2 966 |
mean ex. / |
2 139 | 2 779 |
Turbopack reaches Ready faster (153 ms vs 232 ms) and compiles the first heavy cascade (/) faster (~17 %), but per-route compile averages ~30 % slower than rspack across the next 9 routes in this project.
PROD — bundle size
| Artifact (KB) | rspack | turbopack | Δ |
|---|---|---|---|
.next/static (client) |
46 348 | 53 152 | +15 % (Turbopack) |
.next/server |
35 768 | 114 956 | +222 % (Turbopack) |
.next/standalone |
406 200 | 266 128 | −34 % (Turbopack smaller) |
.next total |
1 345 992 | 435 564 | −68 % (Turbopack smaller; rspack .next/cache is large) |
.next/server is the headline gap on the prod side: Turbopack ships ~3.2× more server-side bytes. Possible cause: experimental.serverMinification: true either no-ops or applies differently under Turbopack; Turbopack also keeps unbundled vendor chunks in server/.
PROD — chunk count and shape
| Metric | rspack | turbopack | Δ |
|---|---|---|---|
Files in .next/static/chunks |
123 | 904 | 7.5× |
Of which .js |
123 | 904 | 7.5× |
| Max single chunk | 30 516 KB (lib-*.js) |
1 780 KB | rspack 17× bigger |
| Median chunk size | 8 KB | 20 KB | — |
| Total bytes (client chunks) | 33 088 KB | 39 824 KB | +20 % |
The numbers are alarming: rspack ships one 30 MB lib-*.js chunk. Total client bytes are only +20 % on the Turbopack side, so this is a chunking shape issue, not a duplicate-bundling issue.
PROD — compile time
3 cold-build runs, .next removed before every run:
| Metric | rspack | turbopack |
|---|---|---|
| Wall clock mean (s) | 30.0 | 12.7 |
| Wall clock min / max | 28.6 / 31.1 | 11.4 / 13.5 |
| "Compiled in" mean (s) | 17.0 | 10.8 |
Turbopack is ~2.4× faster end-to-end on production build (12.7 s vs 30.0 s).
Part 2 — Root cause of the 30 MB vendor chunk
Adding if (process.env.DUMP_SPLIT === '1') to the webpack hook and dumping config.optimization.splitChunks on rspack:
=== DUMP splitChunks (next-rspack@16.2.4) ===
keys: [ 'filename', 'chunks', 'minChunks' ]
cacheGroups keys: []
=== END DUMP ===
cacheGroups is an empty object on the rspack build pipeline. Next.js's webpack pipeline normally injects framework, lib, commons, shared, etc. — none of those are present under next-rspack. Without a lib cacheGroup (which under webpack groups large vendor modules by module.libIdent hash), every ≥160 KB vendor module fell back into the default entry chunk. That is the 30 516 KB lib-*.js.
Turbopack is unaffected because it does not use SplitChunksPlugin at all — it slices the module graph internally.
This looks like the core issue worth flagging upstream: next-rspack does not propagate Next.js's default splitChunks.cacheGroups configuration. Anyone with a non-trivial vendor surface hits the symptom.
Part 3 — Three iterative fixes
We tried three workarounds in next.config.mjs's webpack(config) hook on the rspack side. All cacheGroup edits are gated to the client compiler (config.name !== 'server' && config.name !== 'edge-server').
Attempt A — Edit splitChunks.cacheGroups.lib.name to a hashed function
const lib = config.optimization?.splitChunks?.cacheGroups?.lib
if (lib) {
lib.name = (module) => 'lib-' + sha1(module.identifier()).slice(0, 8)
}Result: no-op. cacheGroups.lib is undefined (Part 2 finding), so the conditional was never entered. The build remained identical to baseline.
Attempt B — Inject explicit cacheGroups with function test and name
cacheGroups: {
framework: { test: /[\\/]node_modules[\\/](react|react-dom|scheduler|next)[\\/]/, name: 'framework', priority: 40, enforce: true, chunks: 'all' },
lib: {
test(module) { return module.size?.() > 160_000 && /[\\/]node_modules[\\/]/.test(module.identifier?.() || '') },
name(module) { return 'lib-' + sha1(module.identifier()).slice(0, 8) },
priority: 30, minChunks: 1, reuseExistingChunk: true, chunks: 'all',
},
commons: { name: 'commons', minChunks: 2, priority: 20, chunks: 'all', reuseExistingChunk: true },
}Result: works, but slow. Chunks: 750. Max chunk: 5 948 KB (commons-*.js). The 30 MB chunk is gone — but the test/name callbacks are JS functions, which the Rust-side splitter must invoke O(N_modules × N_chunks_per_module) times. This adds non-trivial build overhead and is a footgun for anyone copying this pattern.
Attempt C — Static config that matches rspack's own defaults + maxSize
config.optimization.splitChunks = {
chunks: 'all',
minSize: 20_000,
maxSize: 244_000,
cacheGroups: {
default: { minChunks: 2, priority: -20, reuseExistingChunk: true },
defaultVendors: { test: /[\\/]node_modules[\\/]/, priority: -10, reuseExistingChunk: true },
},
}No JS callbacks. maxSize: 244_000 (Next.js's performance.maxAssetSize default) forces any chunk beyond 244 KB to be split.
Result: works, no callback cost, output matches Turbopack's shape.
Side-by-side after fix attempts
| Metric | rspack baseline | rspack B (functions) | rspack C (defaults + maxSize) | Turbopack |
|---|---|---|---|---|
| chunk count | 123 | 750 | 1 003 | 904 |
| total client chunk size (KB) | 33 088 | 33 268 | 34 792 | 39 824 |
| max single chunk (KB) | 30 516 | 5 948 | 1 780 | 1 780 |
| median chunk size (KB) | 8 | 12 | 16 | 20 |
| .next/static (KB) | 46 348 | 46 524 | 48 056 | 53 152 |
| .next/server (KB) | 35 768 | 35 540 | 39 692 | 114 956 |
| prod build wall mean (s) | 30.0 | ~30 (steady) | 37.7 | 12.7 |
C plan brings the max chunk down to 1 780 KB — exactly equal to Turbopack's max — at the cost of ~25 % longer build time (37.7 s vs 30.0 s baseline). The extra time comes from maxSize-driven splitting + chunk metadata overhead, not callback evaluation.
Run-by-run for C: 40.2 s / 33.2 s / 39.6 s. Reported "Compiled in": 27.3 s / 19.9 s / 26.4 s.
Summary table
| Dimension | Winner | Margin |
|---|---|---|
| DEV ready | Turbopack | 1.5× |
| DEV memory | rspack | 2.1× less |
| DEV per-route compile | rspack | 1.3× faster mean |
| DEV first-cascade | Turbopack | 1.2× faster |
| PROD build time | Turbopack | 2.4× faster |
| PROD client total | rspack | 13 % smaller |
| PROD server total | rspack | 3.2× smaller |
| PROD max chunk (default) | Turbopack | 17× smaller |
| PROD max chunk (rspack + C) | tie | identical (1 780 KB) |
| PROD chunk count | depends on policy | Turbopack 7.5× more (default) |
Asks for the rspack plugin team
- Propagate Next.js's default
splitChunks.cacheGroupsinto the next-rspack pipeline. The current emptycacheGroups: {}on rspack causes 30 MB+ single-chunk regressions for any project with a substantial vendor surface, with no warning. Either inject the sameframework/lib/commons/shared/css-loader-importgroups webpack mode has, or document the difference prominently. - Consider whether
maxSizeshould default to a non-zero value on next-rspack (mirroringperformance.maxAssetSize~244 KB), so users don't need to hand-tune it to avoid the 30 MB-chunk symptom. - Performance note: function-valued
cacheGroups.test/cacheGroups.namecost the Rust splitterO(modules × chunks)JS callbacks. Worth warning in docs; users will reach for that pattern when porting webpack configs.
Caveats
- Webpack-only plugins (
code-inspector-plugin,.svg → asset/source) disabled both sides for fairness. .next/serversize gap may not reflect runtime cold-start — not measured here.experimental.optimizePackageImportsset both sides; effectiveness in Turbopack is undocumented for several packages.- Single-run dev memory sample. Turbopack memory has been observed to climb over long sessions.
- First Turbopack build in the prod 3-run errored on
next/font/googlevirtual CSS resolution (Module not found: [next]/internal/font/google/*.module.css); next attempt and all subsequent succeeded. Appears to be a cold-start flake worth tracking. - Tested on
next@16.2.4/next-rspack@16.2.4. Latest stable is16.2.6at time of writing — retest on canary recommended.
Reproduce
# dev
node scripts/bench/dev.mjs rspack
node scripts/bench/dev.mjs turbopack
# prod (n cold runs)
node scripts/bench/prod.mjs rspack 3
node scripts/bench/prod.mjs turbopack 3
# dump rspack's splitChunks config (after temp instrumentation in next.config.mjs)
DUMP_SPLIT=1 BENCH_BUNDLER=rspack NEXT_RSPACK=true next buildFinal next.config.mjs snippet (rspack splitChunks fix)
webpack: (config) => {
// ... your other webpack tweaks ...
if (config.optimization?.splitChunks) {
const isClient = config.name !== 'server' && config.name !== 'edge-server'
if (isClient) {
config.optimization.splitChunks = {
chunks: 'all',
minSize: 20_000,
maxSize: 244_000,
cacheGroups: {
default: { minChunks: 2, priority: -20, reuseExistingChunk: true },
defaultVendors: { test: /[\\/]node_modules[\\/]/, priority: -10, reuseExistingChunk: true },
},
}
}
}
return config
}This is webpack-compatible — same file works for both next-rspack and webpack mode.
|
| server compile | |
|---|---|
no proxy.ts |
1.37s |
with proxy.ts |
25.1s (a second run: 31.1s) |
It scales with the dependency graph, not the app. Same app, same versions, same machine — only node_modules differs:
real packages in node_modules/.pnpm |
no proxy | proxy (cold) | proxy (warm) |
|---|---|---|---|
| 38 | 0.78s | 2.9s | 2.4s |
| 631 (the linked repro) | 0.79s | 8.5s | 9.7s |
| 1997 (a pnpm monorepo) | 1.28s | 27.7s | 55s |
An empty proxy is enough — no imports required:
// proxy.ts
export function proxy() {}→ still 25.6s.
Per-compiler instrumentation (compiler.hooks.compile → compiler.hooks.done) attributes all of it to the server compiler; client and edge-server are unaffected:
[instr] server: compile=27186ms modules=567 entries=...,proxy,...
[instr] edge-server: compile=15ms modules=0
[instr] client: compile=476ms modules=315
Without the proxy entry the same compiler is compile=572ms modules=418. So +149 modules costs +26.6s.
.next/trace puts the time inside the compiler run, not in file tracing:
24916ms run-webpack
24816ms run-webpack-compiler
4443ms collect-build-traces <- separate, healthy
4441ms node-file-trace-build
Where the time goes
--cpu-prof shows the JS thread ~96% idle (31.8s idle out of 32.1s). sample on the build process shows the work happening in binding.darwin-arm64.node tokio threads, dominated by filesystem syscalls (samples over a 5s window, top-of-stack):
__open 911
read 430
stat 366
mkdir 46
__rename 47
lsof during the stall caught it reading files with no relationship to the app — e.g. node_modules/.pnpm/@taplo+cli@0.7.0/node_modules/@taplo/cli/dist/cli.js. That is consistent with the cost scaling with workspace size rather than app size, which would explain it presenting as an unbounded hang in large monorepos.
Cause: the persistent cache
Next.js enables it unconditionally for every next-rspack compiler (next/dist/build/webpack-config.js, isRspack branch):
webpack5Config.experiments.cache = {
type: 'persistent',
buildDependencies,
storage: { type: 'filesystem', directory: cache.cacheDirectory },
version: `${__dirname}|${version}|${configVars}`,
}Disabling it for the server compiler alone fixes it completely:
// next.config.js
webpack(config, ctx) {
if (ctx.isServer) config.experiments = { ...config.experiments, cache: false };
return config;
}| cold | warm | |
|---|---|---|
| default | 27s | 50s |
| server cache off | 1.56s | 1.40s |
Build output was byte-identical in our case, and ƒ Proxy (Middleware) still builds.
Ruled out by measurement
- App size — 600 extra local modules: 4.1s → 4.2s.
transpilePackages— removing it from the failing app: still 27.6s.- Repo location — the minimal app inside the monorepo but with an isolated
node_modules: 1.8s. - Directory count — 2000 fake package directories injected into a small
.pnpm: 4.1s. The trigger is the real resolvable graph, not inode count. outputFileTracingRoot: __dirname→ 29.9soutputFileTracingExcludes: { '*': ['**/*'] }→ 26.9sresolve.symlinks = false→ 26.5s
Two further observations
-
Warm is worse than cold. With the cache on, a second build is slower than the first (50s vs 27s) — it pays to both read and write.
-
The cache does not appear crash-safe. After a dev server was killed mid-write, the next start died with:
panicked at rspack_storage-0.6.7/src/pack/strategy/split/write_scope.rs:107:16: should have bucket pack metasRecovery was
rm -rf .next/cache.
next dev and the webpack bundler are unaffected
next dev boots in ~240ms and compiles the proxy entry in ~310ms with the cache on — no stall. next build --webpack goes 1.6s → 3.0s with the same proxy file, which looks like the ordinary cost of an extra entry.





Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Please use this thread for posting feedback when using the
next-rspackplugin package.When posting, provide the following:
next infoThe Rspack plugin is currently experimental, and is a partner effort with the Rspack team.
All reactions