skip to content

Turbopack

Turbopack is the Rust bundler replacing webpack inside Next, first for dev and now for builds. Interviewers ask about it at concept level: why a new bundler, what incremental compilation buys, and where webpack-config compatibility still bites.

part ofNext.jsoverview, primer and where to startread it →
on this pageshow

explore

questions

5

A Next.js app's `next.config.ts` has a custom `webpack()` function that adds an SVGR rule so `.svg` files import as React components. After the team switches to Turbopack, the rule stops applying. Why, and how do you express that rule for Turbopack?

level: middleimportance: must knowfreq 46%

answer

  1. webpack() is webpack-only, never read
  2. own config key: turbopack
  3. glob to loaders, plus an as field
  4. loaders subset, plugins not at all
  5. keep both blocks while migrating

basics

~20 s

The webpack() function in next.config is only read by webpack, so Turbopack ignores it entirely and Next warns rather than silently honouring it. Port the rule to the turbopack.rules key, which maps a file glob to a list of loaders — a supported subset of webpack loaders, with no plugin equivalent.

solid answer

~50 s

`webpack(config)` is a hook into the webpack build; Turbopack is a different bundler with its own configuration surface, so nothing in that function reaches it. Next surfaces a warning when it sees a custom webpack config while bundling with Turbopack, which is the signal to port rather than a hint that it half-works. The Turbopack equivalent lives under the top-level `turbopack` key in `next.config`: `rules` maps a glob such as `'*.svg'` to `{ loaders: ['@svgr/webpack'], as: '*.js' }`, `resolveAlias` covers path aliases, and `resolveExtensions` covers extension resolution. Turbopack supports a **subset** of webpack loaders — those that stay within the loader API it implements — and has **no plugin API at all**, so anything shipped as a webpack plugin needs a native equivalent or a different place in the pipeline. Keeping both blocks in the file is fine during a migration, since the `webpack()` function still applies whenever you run with `--webpack`.

code

typescript · 24 lines
typescript
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  // Read only when Turbopack is the bundler
  turbopack: {
    rules: {
      '*.svg': { loaders: ['@svgr/webpack'], as: '*.js' },
    },
    resolveAlias: {
      '@ui': './src/components/ui',
    },
  },

  // Read only when webpack is the bundler (next dev --webpack)
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    })
    return config
  },
}

export default nextConfig

go deeper

for a junior

Know that Turbopack does not read the webpack() function in next.config, and that Turbopack's own settings live under a turbopack key — so a bundler switch means porting configuration, not inheriting it.

for a middle

Be able to write the port: a glob mapped to loaders with an as field under turbopack.rules, aliases under resolveAlias, and the awareness that loaders are a supported subset while plugins have no equivalent.

for a senior

Show the migration discipline — audit next.config and the toolchain first, keep both config blocks so --webpack still works, port and verify one rule at a time, and treat the plugin wall as a scheduling decision rather than a surprise.

for a principal

Frame bundler customization as a liability to budget. Every custom rule and plugin is a migration cost the org pays again on the next toolchain move, so set expectations for when a build-time hack is worth taking on at all.

## Why the rule silently stops applying `next.config` exposes a `webpack(config, context)` function whose whole purpose is to hand you webpack's configuration object so you can mutate it. That contract is bundler-specific by construction: the object is a webpack config, the rules you push are webpack `module.rules`, and the only thing that ever reads them is webpack. Turbopack does not consume that object. It is not a webpack-compatible bundler with a translation layer over the config — it is a separate implementation with its own configuration. So the SVGR rule is not misapplied or partially applied; it is simply never seen. Next detects the situation and warns that a custom webpack configuration is present while Turbopack is bundling, which is worth reading rather than scrolling past. ## The Turbopack configuration surface Turbopack's options live under a top-level `turbopack` key in `next.config` (it was previously nested under `experimental.turbo` before being promoted). The three you reach for most: - **`rules`** — an object keyed by glob, each value naming the loaders to run and what the result should be treated as. This is the port target for webpack `module.rules` entries. - **`resolveAlias`** — path aliases, the equivalent of webpack's `resolve.alias`. - **`resolveExtensions`** — the extension list tried during resolution. For the SVGR case: ```ts turbopack: { rules: { '*.svg': { loaders: ['@svgr/webpack'], as: '*.js' }, }, } ``` The `as` field tells Turbopack what the loader's output should be treated as — here, a JavaScript module, because SVGR turns the SVG into a React component. ## Loaders: a subset, not the ecosystem Turbopack implements the webpack loader interface well enough that many loaders run unmodified, and the popular ones generally do. But it is a subset. A loader that reaches into webpack internals — compilation objects, plugin hooks, webpack-specific APIs on the loader context — has nothing to reach for and will fail. When evaluating a migration, the question to ask about each loader is not "is it a webpack loader" but "does it stay inside the loader API." Before reaching for a loader at all, check whether you need one. Turbopack handles CSS, CSS Modules, PostCSS and Sass natively, plus the transforms Next already owns through SWC, so a good share of legacy `webpack()` blocks turn out to be re-implementing something now built in. ## Plugins: no equivalent exists This is the hard wall and the one worth naming explicitly in an interview. webpack's plugin API lets code hook arbitrary points of the compilation lifecycle, and a great deal of tooling is built on it — bundle manipulation, artifact generation, source-map upload to error trackers, custom asset emission. **Turbopack exposes no such API.** A webpack plugin cannot be ported by rewriting configuration; it needs either a Turbopack-native integration published by that tool, or the work moved somewhere else — a separate CLI step in CI, for instance. One more difference that catches teams: the webpack path in Next auto-detected a Babel config file and switched the transform pipeline to Babel. Turbopack does not do that. Custom Babel plugins are not picked up by their config file alone. ## Running the migration Keep both configuration blocks in `next.config` while you migrate. The `webpack()` function still applies whenever the bundler is webpack, so `--webpack` remains a working fallback, and `turbopack.rules` applies whenever Turbopack is bundling. Port one rule at a time, verify the imports it governs actually behave — an SVG rendering as a component rather than a URL string, for example — and delete the webpack block only once nothing runs on webpack any more.

  • Your build depends on a webpack plugin, not a loader. What are your options under Turbopack?
    Porting the configuration will not help — Turbopack has no plugin API, so there is nothing to hook. The realistic options are a Turbopack-native integration published by that tool, moving the work out of the bundler into a separate CI step, dropping the capability, or staying on `--webpack` for builds until an equivalent exists. Treat the last one as temporary and revisit it each Next release.
  • Which webpack loaders are likely to work under Turbopack, and which are not?
    Loaders that stay inside the loader API — read source in, return transformed source out, using the standard loader context — generally run unmodified, which covers most popular ones. Loaders that reach into webpack internals such as the compilation object or plugin hooks have nothing to bind to and will fail. Check the loader's implementation rather than assuming, and confirm the transform actually applied.
  • Before porting a webpack rule at all, what should you check?
    Whether Turbopack already handles it. CSS, CSS Modules, PostCSS and Sass are built in, and TypeScript and JSX go through SWC as part of Next itself. A lot of `webpack()` blocks in older projects predate those built-ins and re-implement them, so the cleanest migration for those entries is deletion rather than translation.

saying these in an interview costs you the question

  • Believes Turbopack reads and translates the existing webpack() config
  • Thinks any webpack plugin works if you list it under turbopack
  • Assumes every webpack loader runs unchanged under Turbopack
  • Says a Babel config file is picked up automatically like it was with webpack
  • Deletes the webpack() block before the team has stopped using --webpack

context

open as a page

In a Next.js project, what is Turbopack, and what does running `next dev --turbopack` do differently from running the dev server on webpack?

level: juniorimportance: should knowfreq 58%

basics

~20 s

Turbopack is Next.js's Rust-based bundler, built to replace webpack for both the dev server and production builds. next dev --turbopack starts the dev server on Turbopack; in Next 16 Turbopack is the default for dev and build, and --webpack opts back out.

open as a page

Turbopack is described as compiling incrementally and on demand in `next dev`. What work happens when, and why can the first visit to a route still take a noticeable moment even though the dev server started instantly?

level: middleimportance: should knowfreq 42%

basics

~20 s

Turbopack's dev server compiles nothing up front: it compiles a route the first time you request it, so a cold route pays for its own module graph. After that, an edit recomputes only the cached units whose inputs changed and pushes an update, which is why edits feel instant while first visits do not.

open as a page

Your team wants to move a large Next.js app's production builds from webpack to Turbopack. How would you validate that switch before you ship on it?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Build the same commit with both bundlers and compare: does every route compile, are the emitted routes and their sizes equivalent, do source maps still reach your error tracker, and does the built app behave the same under smoke tests. Ship behind the ability to fall back to webpack, then watch build times and runtime errors.

open as a page

A Next.js app depends on a webpack plugin that has no Turbopack equivalent, so the team cannot adopt Turbopack builds. As the lead, how do you decide between staying on webpack, replacing the tooling, or splitting the pipeline?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Price both sides: what the faster builds and dev loop are worth across the team, against the cost of replacing the plugin's function or maintaining a split pipeline. Then pick an option with an explicit review date, because webpack is the legacy path in Next 16 and staying on it is a decision that expires.

open as a page