| | |

Next.js 22 ▲ Turbopack Production — Stable bundler & filesystem caching

⏱️ Estimated read: 12 min | |

Turbopack is Next.js’s Rust-based bundler, built to replace webpack with an incremental computation engine. It reached stable status for production builds in Next.js 16 and became the default bundler for all new projects, delivering 2–5× faster production builds and up to 10× faster Fast Refresh . The filesystem cache, which persists compilation artifacts across runs, was enabled by default for development in Next.js 16.1.0 and for builds in Next.js 16.3.0 . The two milestones together are what complete the transition from a development-only optimization to a production-grade bundler.

This chapter covers the production stability milestone, the default bundler switch and its webpack escape hatch, the filesystem cache for both development and builds, the turbopack configuration key, and the CI configuration that determines whether the cache actually saves time.

Key point: Turbopack is the default for next build in Next.js 16 and later. The filesystem cache lives in .next/cache/turbopack and is enabled by default for builds since 16.3.0. In a containerized or ephemeral CI environment, the cache only helps if .next/cache is restored before the build. If the environment never restores it, disable the cache rather than paying the write cost.


Why Turbopack became the production default

The webpack bottleneck. webpack is a JavaScript-based bundler. Its compilation model parses and transforms the entire module graph in a single process, and the work does not persist between builds. On a large application, a cold production build can take minutes, and the work is repeated from scratch on every run. Turbopack is written in Rust and uses an incremental computation model: the result of every function is cached, and only the functions whose inputs changed are recomputed .

The stability milestone. Turbopack was stable for development since Next.js 15, but the production build path was experimental. Next.js 16 made it stable for both development and production, and the release notes state that it is now the default bundler “with no configuration required” . Stability here is not just about correctness; it is about feature coverage, including the loaders and configuration that production builds depend on.

The cache milestone. The filesystem cache for development was enabled by default in Next.js 16.1.0. The cache for production builds was enabled by default in Next.js 16.3.0 . The cache is what makes the second build faster than the first, and it is the mechanism that closes the gap between a cold CI build and a warm local build.

The CI reality check. The cache is not universally beneficial. A measured experiment found that a warm build can be slower than a cold build at a certain project size, and the cache directory can grow from roughly 5 GB to 12 GB across two runs . The speedup depends on the project, the machine, and whether the CI environment preserves .next/cache. The cache is a build artifact with a real cost, not a free optimization.


a. The production build and the webpack fallback

A production build with Turbopack is the default. The next build command uses Turbopack without any flag. A project that needs the webpack bundler can opt out explicitly.

# Default: Turbopack
next build

# Opt out: webpack
next build --webpack

# Development: same default, same fallback
next dev --webpack

The --webpack flag is the escape hatch for a project with a custom webpack configuration that Turbopack does not yet support. The Next.js 16 release notes state that apps with custom webpack setups can continue using webpack by passing the flag . The flag is available for both next dev and next build, which means a project can use Turbopack for development and webpack for production, or the reverse, during a migration.

The fallback is not a long-term solution. A project that depends on a webpack plugin which hooks into the compilation lifecycle, such as webpack-bundle-analyzer, has no Turbopack equivalent for that workflow and must keep the webpack path for as long as the workflow is needed. The flag exists so that the migration can be incremental rather than all-or-nothing.


b. The turbopack configuration key

The turbopack key in next.config.ts is the configuration surface for Turbopack-specific settings: loaders, resolve aliases, and the root directory. It is not a one-to-one replacement for webpack’s module.rules.

// next.config.ts
import type { NextConfig } from 'next'
import path from 'node:path'

const nextConfig: NextConfig = {
  turbopack: {
    root: __dirname,
    resolveAlias: {
      '@': path.resolve(__dirname, 'src'),
    },
    rules: {
      '*.svg': {
        loaders: ['@svgr/webpack'],
        as: '*.js',
      },
    },
  },
}

export default nextConfig

The root option tells Turbopack where the project root is. This matters in a monorepo or a workspace, where the nearest package-lock.json may not be the file that defines the project boundary. The resolveAlias option is the equivalent of webpack’s resolve.alias. The rules object is the loader configuration, keyed by file pattern, with the loaders array and the as output type .

The configuration is narrower than webpack’s. A webpack plugin that participates in the compilation lifecycle—emitting assets, hooking into the build phases, or modifying the module graph—cannot be expressed as a Turbopack rule. The project that needs such a plugin keeps the webpack fallback for the workflow that requires it.


c. The filesystem cache for builds and development

The filesystem cache persists Turbopack’s work between commands. The development cache is stored in .next/dev/cache/turbopack, and the build cache is stored in .next/cache/turbopack . Both are enabled by default in the current release.

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  experimental: {
    turbopackFileSystemCacheForDev: true,
    turbopackFileSystemCacheForBuild: true,
  },
}

export default nextConfig

The turbopackFileSystemCacheForDev option was enabled by default in 16.1.0. Restarting the dev server reuses the previous compilation, which is the mechanism that makes the second next dev start faster than the first . The turbopackFileSystemCacheForBuild option was enabled by default in 16.3.0. A subsequent next build starts warm and skips the work the previous build already did .

The cache has a real cost. A measured build cache in one project was approximately 5 GB after a cold build, and the warm build reduced the compile time from 105 seconds to 22 seconds . The size is the trade-off for the speed, and the cache must be managed as a build artifact, not committed and not included in the deployment image unless the deployment process reads it.


d. The CI configuration that determines whether the cache helps

The cache only saves time if .next/cache is restored before the build. A self-hosted build that reuses the same working directory gets the cache automatically. A containerized build starts from a clean layer and does not carry the cache over unless the directory is mounted or cached explicitly. A CI provider needs a cache configuration for .next/cache.

# GitHub Actions excerpt
- uses: actions/cache@v4
  with:
    path: .next/cache
    key: ${{ runner.os }}-next-${{ hashFiles('**/package-lock.json') }}
- run: npm ci
- run: npm run build

The cache key should include the lockfile hash so that a dependency change invalidates the cache. A project whose CI environment never preserves .next/cache should set turbopackFileSystemCacheForBuild: false. The documentation states this directly: if the build environment never preserves the cache, disable the option to skip writing a cache that will not be read . The write itself costs time, and the directory is large, so a write without a subsequent read is a net loss.

The cache is not a universal win. The measured experiment above found a warm build that was slower than a cold build, and a cache directory that grew from 5.1 GB to 12 GB across two runs . The lesson is to measure the cache on the specific project and the specific CI environment before treating it as a default. A small or medium project may not save enough compile time to justify the write and restore, and the cache size can grow faster than the compile time shrinks.


Complete Example Session

// ============================================
// PART 1: THE DEFAULT BUILD
// ============================================
// next build
// Turbopack is the default bundler.
// No flag is required.
# ============================================
# PART 2: THE WEBPACK FALLBACK
# ============================================
next build --webpack
# For a custom webpack configuration that
# Turbopack does not yet support.
// ============================================
// PART 3: THE TURBOPACK CONFIG
// ============================================
// next.config.ts
const nextConfig: NextConfig = {
  turbopack: {
    root: __dirname,
    resolveAlias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
}
// ============================================
// PART 4: THE LOADER RULE
// ============================================
const nextConfig: NextConfig = {
  turbopack: {
    rules: {
      '*.svg': {
        loaders: ['@svgr/webpack'],
        as: '*.js',
      },
    },
  },
}
// ============================================
// PART 5: THE FILESYSTEM CACHE
// ============================================
const nextConfig: NextConfig = {
  experimental: {
    turbopackFileSystemCacheForDev: true,
    turbopackFileSystemCacheForBuild: true,
  },
}
// ============================================
// PART 6: THE CACHE LOCATIONS
// ============================================
# Dev cache:   .next/dev/cache/turbopack
# Build cache: .next/cache/turbopack
# ============================================
# PART 7: THE CI CACHE
# ============================================
- uses: actions/cache@v4
  with:
    path: .next/cache
    key: next-${{ hashFiles('package-lock.json') }}
- run: npm ci && npm run build
// ============================================
// PART 8: THE CACHE DISABLE
// ============================================
const nextConfig: NextConfig = {
  experimental: {
    turbopackFileSystemCacheForBuild: false,
  },
}
// For an environment that never restores .next/cache.
// ============================================
// PART 9: THE CACHE MEASUREMENT
// ============================================
# Large project:
#   Cold build: 105s, cache written (4.8 GB)
#   Warm build: 22s, cache restored
#
# Medium project, certain CI:
#   Warm build slower than cold, cache grew to 12 GB
#
# Measure before enabling as a default.
// ============================================
// PART 10: THE DECISION
// ============================================
# Large project + persistent CI  → enable the build cache
# Small project + ephemeral CI   → disable the build cache
# Custom webpack configuration   → next build --webpack

The ten parts covered the default build, the webpack fallback, the Turbopack config, the loader rule, the filesystem cache, the cache locations, the CI cache, the cache disable, the cache measurement, and the decision.


Quick Reference

The bundler

CommandBundler
next devTurbopack (default)
next buildTurbopack (default)
next build --webpackwebpack (fallback)
next dev --webpackwebpack (fallback)

The filesystem cache

OptionDefaultLocation
turbopackFileSystemCacheForDevtrue (16.1.0+).next/dev/cache/turbopack
turbopackFileSystemCacheForBuildtrue (16.3.0+).next/cache/turbopack

The cache milestones

VersionMilestone
15.5.0Experimental on canary
16.0.0Beta with separate flags
16.1.0Default for development
16.3.0Default for builds

The turbopack config keys

KeyPurpose
rootProject root for resolution
resolveAliasModule aliases
rulesLoader configuration
rules[].loadersLoader array
rules[].asOutput type

Best Practices

✅ Do This:

// Set the project root explicitly in a monorepo
turbopack: { root: __dirname }                               // ✅
// Use resolveAlias for the path aliases
resolveAlias: { '@': path.resolve(__dirname, 'src') }        // ✅
# Cache .next/cache in CI with a lockfile key
path: .next/cache
key: next-${{ hashFiles('package-lock.json') }}              // ✅
// Disable the build cache when CI never restores it
turbopackFileSystemCacheForBuild: false                      // ✅

❌ Don’t Do This:

# Keep the webpack fallback indefinitely for a supported config
next build --webpack                                         // ❌
// Enable the build cache in an ephemeral CI with no restore
turbopackFileSystemCacheForBuild: true                       // ❌
# Commit .next/cache to the repository
git add .next/cache                                          // ❌
// Assume a webpack plugin works as a Turbopack rule
rules: { '*.css': { loaders: ['some-webpack-plugin'] } }     // ❌

Common Pitfalls

PitfallWhy It HappensFix
Custom webpack loader failsTurbopack does not support itUse --webpack for that workflow
Warm build slower than coldCache overhead exceeds the savingsMeasure; disable the build cache
Cache directory fills the diskThe cache grows to several GBSet a size limit or disable on small projects
Alias does not resolveresolveAlias missingAdd the alias to turbopack
Monorepo uses the wrong rootroot not setSet root: __dirname

Real-World Examples

1. The default build

next build

2. The webpack fallback

next build --webpack

3. The turbopack root

turbopack: { root: __dirname }

4. The resolve alias

turbopack: { resolveAlias: { '@': './src' } }

5. The loader rule

turbopack: { rules: { '*.svg': { loaders: ['@svgr/webpack'], as: '*.js' } } }

6. The build cache

experimental: { turbopackFileSystemCacheForBuild: true }

7. The CI cache

uses: actions/cache@v4

8. The cache disable

experimental: { turbopackFileSystemCacheForBuild: false }

9. The cache measurement

Cold: 105s → Warm: 22s

10. The decision

Large + persistent CI → cache; small + ephemeral → no cache

Visual

The Turbopack default

┌─────────────────────────────────────────────────────────────┐
│  next build                                                  │
│       │                                                      │
│       ├── Turbopack (default)                                │
│       │     ├── 2–5× faster than webpack                     │
│       │     └── filesystem cache enabled                     │
│       │                                                      │
│       └── --webpack (opt-out)                                │
│             └── custom webpack configuration                 │
└─────────────────────────────────────────────────────────────┘

The cache lifecycle

┌─────────────────────────────────────────────────────────────┐
│  First build (cold)                                          │
│       │                                                      │
│       ▼                                                      │
│  Cache written to .next/cache/turbopack                     │
│       │                                                      │
│       ▼                                                      │
│  Second build (warm)                                         │
│       │                                                      │
│       ▼                                                      │
│  Cache restored, work skipped                                │
│       │                                                      │
│       ▼                                                      │
│  Faster build                                                │
└─────────────────────────────────────────────────────────────┘

The CI cache decision

┌─────────────────────────────────────────────────────────────┐
│  Is .next/cache restored before the build?                   │
│       │                                                      │
│       ├── Yes ──► enable the cache                          │
│       │                                                      │
│       └── No ──► disable it                                  │
│             (turbopackFileSystemCacheForBuild: false)        │
└─────────────────────────────────────────────────────────────┘

The cache measurement

┌─────────────────────────────────────────────────────────────┐
│  Large project:                                              │
│    Cold: 105s, Warm: 22s ──► cache is a win                 │
│                                                              │
│  Certain medium project:                                     │
│    Cold: 113s, Warm: 360s ──► cache is a loss               │
│                                                              │
│  Measure before enabling.                                    │
└─────────────────────────────────────────────────────────────┘

Summary

ItemValue
Turbopack production statusStable in Next.js 16
Default bundlerTurbopack for next dev and next build
Speed improvement2–5× faster builds, up to 10× faster Fast Refresh
Webpack fallback--webpack flag
Dev cache defaultEnabled since 16.1.0
Build cache defaultEnabled since 16.3.0
Cache locations.next/dev/cache/turbopack, .next/cache/turbopack
Turbopack config keyturbopack in next.config.ts
CI requirement.next/cache must be restored before the build
Disable optionturbopackFileSystemCacheForBuild: false

Key takeaways:

  • Turbopack is the default production bundler in Next.js 16. It is stable for both development and production, and it delivers 2–5× faster builds and up to 10× faster Fast Refresh without configuration. A project with a custom webpack setup can opt out with next build --webpack .
  • The filesystem cache is enabled by default for builds since 16.3.0. The cache persists Turbopack’s compilation work in .next/cache/turbopack and makes subsequent builds start warm. The development cache has been default since 16.1.0 and lives in .next/dev/cache/turbopack .
  • The cache only helps if .next/cache is restored. A self-hosted build that reuses the working directory gets the cache automatically. A containerized or ephemeral CI build needs an explicit cache mount or a CI cache action. A build environment that never restores the cache should set turbopackFileSystemCacheForBuild: false .
  • The cache is not universally beneficial. A measured CI experiment found that the cache can make a build slower at a certain project size, and the cache directory can grow to several gigabytes. The cache should be measured on the specific project and CI environment before it is enabled as a default .
  • The turbopack key is the configuration surface. It holds the root, the resolveAlias map, and the loader rules. It is not a one-to-one replacement for webpack’s module.rules, and a webpack plugin that participates in the compilation lifecycle cannot be expressed as a Turbopack rule .
  • The webpack fallback exists for the custom configurations Turbopack does not yet support. A project that depends on a compilation-lifecycle plugin must keep the webpack path for the workflow that needs it. The fallback is available for both next dev and next build.

Remember: Turbopack is no longer the experimental bundler. It is the default production path in Next.js 16, and the filesystem cache is the mechanism that makes repeated builds faster. The cache is a build artifact, not a source file: it lives in .next/cache, it grows large, and it only helps when the environment preserves it. Enable it where it is measured to help, disable it where it is not, and use the --webpack flag only when the project’s custom configuration requires it.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!