Turbopack: What’s New in Next.js 16.3
As the Next.js 16.3 Preview nears a stable release, we’re sharing a series of posts about what’s inside. Our previous posts cover new Instant Navigation features and the latest AI improvements. This third post details the latest improvements to the Turbopack bundler within Next.js.
With Next.js 16.3, Turbopack’s latest stable release focuses on compiler performance. Many of the newest features are centered around reducing CPU and Memory usage, speeding up build times, and improving runtime experience.
- Reducing dev server memory usage by up to 90%
- Persistent file system cache for faster builds
- Experimental Rust React Compiler support
import.meta.globAPI support- Faster HMR and dev startup
Reducing memory usage in dev mode
Turbopack’s core design is focused on incremental compilation. By caching the work it previously did, it avoids recompiling files that haven’t changed. When developing large Next.js applications, this means compile time is proportional to the size of your changes, not the size of your route.
In pursuing this design, we made a very deliberate trade-off: caching more results in memory, for reduced CPU usage. Since Turbopack first launched, though, memory usage has been at a premium. Coding agents, IDEs, typecheckers, and linters all run at dev time, and each consumes a significant chunk of system memory. Over the last three months, the Turbopack team has been committed to reducing its contribution to system memory pressure. With an upgrade to 16.3, developers should immediately see less memory usage for long-running dev sessions.
Memory usage after compiling 50 routes
~90% smaller
Much of this was achieved through small incremental wins: compressing data structures and avoiding storing data longer than was necessary. The biggest win, though, comes from a new ability to evict much of the in-memory cache. Leveraging the file-system persistence feature that was first introduced in Next.js 16.1, Turbopack is able to remove cached results from memory. This avoids unbounded growth of memory in dev sessions, since the memory cache no longer holds onto every visited route.
Memory eviction requires the development filesystem cache to be enabled. In 16.3, both of these options are on by default. It can be disabled when investigating cache or development performance with the experimental turbopackMemoryEviction config value:
const nextConfig = {
experimental: {
turbopackMemoryEviction: false, // disables memory eviction, default value is 'full'
},
};
There is no single reduction percentage that applies to every application. Individual results depend on the size of the route graph, how much of it was touched during the development session, and how long the session was running.
File System cache for builds
Persisting the Turbopack memory cache to disk has been speeding up next dev sessions since the 16.1 release. After months of hardening in production with Vercel’s own sites, the same persisted cache is now available for next build.
Turbopack compile time for next build
~1.4× faster
~5.5× faster
With persistent disk cache, builds can take advantage of previously computed work and reduce the time it takes to compile your static assets. CI setups can take advantage of this by copying the generated .next directory from one run to the next. When Turbopack sees the cache at the start of a build, it reads entries from disk before compiling any new changes.
Persistent cache for builds can be enabled with the turbopackFileSystemCacheForBuild config flag.
const nextConfig = {
experimental: {
// Enable filesystem caching for `next build`
turbopackFileSystemCacheForBuild: true,
}
}
Experimental Rust React compiler
Next.js has provided stable support for the React Compiler since the first 16.0 release. Until now, the React Compiler has only been available as a Babel transform. On larger applications, we observed that it could slow down builds while waiting for JS execution resources. Recently, the React team published a native Rust port of the compiler, which we were quick to integrate into Turbopack.
Promising early tests against large React apps like v0 showed compilation wins of 20-50%, so we are releasing the native compiler integration as an experimental feature to drive more adoption.
To test out the Rust React Compiler, enable the compiler and use the experimental turbopackRustReactCompiler flag to use the native version:
const nextConfig = {
// enable the compiler
reactCompiler: true,
experimental: {
// use the Rust version, instead of the OG Babel one
turbopackRustReactCompiler: true,
}
}
There are many ways to configure the React Compiler for features like opt-in functionality. You can read the full documentation for more details.
Turbopack now supports the Vite-compatible import.meta.glob API:
const posts = import.meta.glob('./posts/*.mdx');
This API can import all modules that match this pattern, without hardcoding their names. The result is an object keyed by the matching file paths. By default, each value is an async function that loads the module:
for (const path in posts) {
const post = await posts[path]();
}
Use eager: true to import each match immediately:
const posts = import.meta.glob('./posts/*.mdx', {
eager: true,
})
The implementation also supports named imports, multiple patterns, negative patterns, custom search path, query strings for loaders, and generated TypeScript types.
This functionality is powered by Turbopack’s file watcher. When a file is added to or removed from this match set, it will trigger recompilation in dev mode, so your site always reflects the latest changes. This API is perfect for fetching sets of similar documents, like product descriptions or blog posts. We also expect that library developers will benefit from this API existing across the broader JS ecosystem.
import.meta.glob is available as a Turbopack feature, and will not work for Next.js apps built with the --webpack option.
See the import.meta.glob reference for all of the available options.
HMR improvements
By analyzing the performance of Turbopack in large Next.js apps at Vercel, we identified a number of performance improvements that could benefit all Turbopack users. Much of that investigation centered around making HMR subscriptions more efficient. One significant change streamlined the tracking of chunks that are loaded on a page. By reducing multiple subscriptions to a single one, we were able to reduce dev server cold start by over 15% on complex apps.
This is only the beginning of our HMR resource investigations, and we expect to deliver more memory and cold-start improvements in future Next.js releases.
Smaller runtime size
Turbopack ships runtime code to every route that allows it to resolve modules and dynamically fetch new chunks. This also includes code for loading WebAssembly, workers, and top-level async modules. Not every Next.js application uses that functionality, though. Now Turbopack will only ship those features when they’re needed, and avoids shipping extra runtime code the rest of the time.
Local PostCSS configuration
Monorepos may need different PostCSS transforms for different packages.
The experimental turbopackLocalPostcssConfig option lets Turbopack resolve the configuration closest to each CSS file before falling back to the project root:
const nextConfig = {
experimental: {
turbopackLocalPostcssConfig: true,
},
};
This allows package-level CSS to use a local configuration while application CSS continues to use the root configuration.
Compatibility and reliability
Next.js 16.3 rolls up all of the fixes from the 16.2 patch line and adds more improvements across module resolution, tracing, and HMR, including:
- Correct file URLs for
import.meta.urlon Windows - Retry chunk fetching on failure
- Better support for
createRequire(new URL(..., import.meta.url)) - Correct
worker_threadsURL resolution - Support for the
module-syncexport condition - Better errors when webpack loaders crash
- CSS HMR fixes in Safari