Turbopack is the default now
Next.js 16 builds and serves with Turbopack by default. For most projects the switch is invisible and faster. For some it surfaces failures that webpack tolerated, because Turbopack resolves modules, handles CSS and manages memory differently. These are the ones we have hit on real projects, with what they look like and what fixed them.
1. Out of memory during build
Looks like: FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory, or the CI runner killed with exit code 137, usually during "Creating an optimized production build" or during static generation on a site with hundreds of routes.
Why: Turbopack holds the module graph in memory, and a large graph (many routes, large dependencies, big MDX content imported as modules) plus the static generation workers can exceed Node's default heap on a 4 GB runner.
Fixes, in order:
- Raise the heap:
NODE_OPTIONS=--max-old-space-size=6144 next build. Blunt and often sufficient. - Reduce static generation concurrency:
experimental.cpusinnext.config, or the newerstaticGenerationMaxConcurrency, so fewer workers hold data at once. - Stop importing content as modules. A thousand MDX files imported into the graph is a thousand modules. Read them at build with
fsin a cached loader instead, so they are data, not code. - Check for a dependency pulling in a huge tree (moment with all locales, a full icon library, a charting library with every chart). The bundle analyser shows it.
- Use a larger CI runner. Sometimes the honest answer.
The persistent cache (.next/cache restored between CI runs) reduces repeat build memory and time considerably; make sure CI restores it.
2. Linked workspace packages not resolving
Looks like: Module not found: Can't resolve '@acme/ui' in Turbopack, working fine in webpack. Or the package resolves but its 'use client' components are treated as server components. Or changes in the linked package do not trigger reloads.
Why: In a monorepo (pnpm, Yarn workspaces, npm workspaces), @acme/ui is a symlink into packages/ui. Turbopack resolves symlinks to their real paths and applies the project root's rules to them; a package whose package.json exports map does not include the entry Turbopack asks for, or that ships uncompiled TypeScript without being declared as such, fails.
Fixes:
- Add the package to
transpilePackagesinnext.configso Turbopack compiles its source:transpilePackages: ['@acme/ui']. - Make sure the package's
exportsfield has bothimportandtypesconditions, and includes any subpath you import (@acme/ui/button). - If the package is outside the Next.js project directory, set
turbopack.root(oroutputFileTracingRoot) to the monorepo root so Turbopack knows the boundary. - For
'use client'not being honoured, ensure the directive is the first statement in the source file Turbopack actually reads (the transpileddistmay have lost it; pointexportsat source or preserve directives in the package build).
3. CSS Modules not hot-reloading
Looks like: editing a .module.css file in next dev does not update the browser until a full reload; or updates land but class names change and styles flash; or global CSS updates and CSS Modules do not.
Why: Mostly historical Turbopack bugs in the 14 and 15 series, fixed in later releases; occasionally a project configuration (a CSS Module imported from a server component and a client component via different paths, or a PostCSS config that Turbopack does not apply to modules).
Fixes:
- Update. Most CSS Modules HMR issues are fixed in 15.x and 16.
- Import each CSS Module from one place, ideally the component that uses it, not from a barrel file.
- Check
postcss.configis CommonJS or the supported format and that plugins are Turbopack-compatible;postcss-importin particular conflicts with Turbopack's own handling. - If a CSS Module and a global stylesheet define the same custom property, the update order can look like a "not reloading" bug; it is a specificity issue.
4. Webpack loaders that have no Turbopack equivalent
Looks like: Error: Turbopack does not support webpack loaders by default or a build that ignores a webpack() function in next.config.
Why: The webpack config function is not run by Turbopack. Custom loaders (for SVGs as components, for YAML, for GraphQL files) need declaring in turbopack.rules.
Fix:
// next.config.ts
const nextConfig = {
turbopack: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
}Many webpack loaders work under turbopack.rules because they use the compatible subset of the loader API. Some do not; for those, the fix is a different approach (import SVGs as URLs and use <img>, or pre-process YAML to JSON at build).
5. Environment and resolution surprises
resolve.aliasin webpack becomesturbopack.resolveAlias.resolve.extensionsbecomesturbopack.resolveExtensions; the default excludes some extensions webpack included.- Node built-ins in client code error rather than being polyfilled. If a dependency imports
fsin a client path, it was always wrong; Turbopack tells you. process.envin the browser only works forNEXT_PUBLIC_variables, as before, but the error is now at build rather than a silentundefined.
6. Falling back
next build --webpack uses the webpack bundler for a build when Turbopack blocks a release and there is no time to fix it. It is a fallback, not a plan; it will not be there forever, and the underlying issue is usually a project problem that Turbopack made visible.
Diagnosing quickly
- Read the whole error. Turbopack's messages name the file and the resolution path.
- Try a clean build: delete
.next, rebuild. - Reproduce with
next build --webpack. If webpack also fails, it is not Turbopack. - Check the Next.js release notes for the version; many of these are listed as fixed.
- Search the specific message in the Next.js repository issues; Turbopack issues are well-triaged.
Where this sits
Every one of these came up moving client sites to Next.js 16, and each was fixed in under an hour once identified. The OOM one is the one to expect on any site with hundreds of routes, and the heap flag plus the persistent cache are the first two lines of the CI config for every Next.js project we ship.