Turbopack
Core Idea
Turbopack is the Rust-based incremental bundler built into Next.js and the default bundler as of v16.0.0 for both next dev and next build, offering a unified graph, incremental caching, and lazy bundling.
Key Concepts
- Unified graph: single graph covers all output environments (client/server) instead of stitching separate compiler outputs together.
- Incremental computation: parallelized across cores, cached down to the function level, persisted to disk between runs.
- Lazy bundling: only bundles what the dev server actually requests, cutting initial compile time/memory.
import.meta.env: Turbopack-only, Vite-compatible env metadata object (DEV, PROD, MODE, BASE_URL, SSR), statically analyzed for dead-branch elimination.
import.meta.glob(): Turbopack-only, Vite-compatible glob-import API; lazy (thunks) by default, { eager: true } for direct imports, plus import, query, base, caseSensitive options.
- Magic comments:
turbopackIgnore, turbopackOptional (Turbopack-only) alongside webpack-compatible webpackIgnore; apply to dynamic import(), require(), require.resolve(), new Worker().
turbopack config key: next.config.js namespace for rules (loaders), resolveAlias, resolveExtensions, ignoreIssue.
--webpack flag: explicit opt-out back to Webpack, needed on platforms without native bindings (falls back to WASM, which doesn't support Turbopack).
Code Examples
if (import.meta.env.DEV) {
console.log('development mode')
}
const { MODE, SSR } = import.meta.env
const baseUrl = import.meta.env['BASE_URL']
// Lazy (default): thunks
const modules = import.meta.glob('./dir/*.js')
for (const path in modules) {
const module = await modules[path]()
}
// Eager
const eagerModules = import.meta.glob('./dir/*.js', { eager: true })
// Named export + query string
const defaults = import.meta.glob('./dir/*.js', { import: 'default' })
const rawFiles = import.meta.glob('./dir/*.txt', { query: '?raw' })
// Multiple patterns + negation
const combined = import.meta.glob(['./src/**/*.js', '!**/*.test.js'])
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
turbopack: {
rules: {
'*.txt': { condition: { query: '?raw' }, type: 'text' },
},
resolveAlias: { underscore: 'lodash' },
resolveExtensions: ['.mdx', '.tsx', '.ts', '.jsx', '.js', '.json'],
},
}
export default nextConfig
- O que demonstra: as duas APIs exclusivas do Turbopack (
import.meta.env, import.meta.glob) e a configuração básica via chave turbopack no next.config.ts.
Reference Tables
| Category | Status |
|---|
| JS/TS, ESNext, CommonJS, ESM | Supported (SWC-based) |
| Babel | Supported automatically since Next.js 16 if a Babel config file is detected; node_modules excluded unless babel-loader manually configured |
| JSX/TSX, Fast Refresh, RSC | Supported |
| Root layout auto-creation | Unsupported — must create manually |
Global CSS, CSS Modules, CSS Nesting, @import, PostCSS | Supported |
| Sass/SCSS | Supported; sassOptions.functions NOT supported (use webpack) |
| Less | Planned via plugins, not yet default |
| Lightning CSS | In use for CSS transforms; some legacy CSS Modules features unsupported |
| Static assets, JSON imports | Supported |
| Path aliases, manual aliases, custom extensions | Supported via tsconfig.json / turbopack config |
| AMD | Partially supported |
| Webpack plugins | Not supported (loaders are) |
Yarn PnP, experimental.urlImports, experimental.esmExternals | Not planned |
| Magic comment | Webpack | Turbopack |
|---|
webpackIgnore: true | Yes | Yes |
turbopackIgnore: true | No | Yes |
turbopackOptional: true | No | Yes |
webpackOptional: true | No | No |
| Key experimental option | Default (dev) | Default (build) |
|---|
turbopackFileSystemCacheForDev | true | N/A |
turbopackFileSystemCacheForBuild | N/A | true |
turbopackMinify | false | true |
turbopackSourceMaps | true | productionBrowserSourceMaps |
turbopackRemoveUnusedImports/Exports | false | true |
turbopackScopeHoisting | false (always off in dev) | true |
turbopackModuleIds | 'named' | 'deterministic' |
Anti-patterns
- Using webpack's
~ tilde syntax for Sass node_modules imports: unsupported; drop the ~ or configure turbopack.resolveAlias: { '~*': '*' }.
- Relying on
sassOptions.functions custom JS-in-Sass functions: architecturally impossible under Turbopack's Rust engine; requires --webpack.
- Assuming identical CSS decimal precision to webpack: Lightning CSS uses 5-digit precision vs webpack's 10 (e.g.
line-height: 1.47059 vs 1.4705882353), which can shift pixel-level rendering.
- Expecting webpack plugins to work: Turbopack has no plugin system, only loader support; find Turbopack-native alternatives or stay on webpack.
- Relying on CSS import order across side-effect-free JS modules: Turbopack strictly follows JS import order for CSS Modules, which can differ from webpack's occasional reordering.
Key Takeaways
- Turbopack is zero-config for the vast majority of JS/TS/CSS/React use cases; explicit
turbopack config is only needed for aliases, custom loaders, or extensions.
import.meta.env and import.meta.glob are Turbopack-exclusive Vite-compatible APIs unavailable under webpack.
- Filesystem caching (
turbopackFileSystemCacheForDev/ForBuild) persists compiler artifacts to disk, requiring the build environment to preserve .next/cache between runs to benefit.
- Migrating from webpack surfaces subtle diffs: CSS Modules ordering, Sass
~ imports, decimal precision, and dropped webpack-plugin support are the top gotchas.
next dev --internal-trace generates a .next-profiles/trace-turbopack.bin file for reporting performance/memory issues upstream.
Connects To
- ch269 next-cli:
--turbopack/--webpack CLI flags and --experimental-cpu-prof profiling.
- ch285 glossary: "Turbopack" glossary entry cross-references this page.