Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/shuding/nextra/llms.txt

Use this file to discover all available pages before exploring further.

Turbopack is a Rust-based incremental bundler built into Next.js that dramatically speeds up development server startup and hot-module replacement compared to the default Webpack bundler. Nextra fully supports Turbopack in development mode and automatically configures the necessary loaders and aliases so your MDX content, page maps, and theme all work without any manual setup.

Enabling Turbopack

To enable Turbopack for your development server, add the --turbopack flag to your next dev command:
package.json
"scripts": {
  "dev": "next dev --turbopack",
  "build": "next build",
  "start": "next start"
}
Without the --turbopack flag, Next.js uses Webpack under the hood — a JavaScript-based bundler. Turbopack is the Rust-based replacement and is only used during development; next build always uses Webpack for production builds (for now).
On older versions of Next.js (before Turbopack was stable), the flag was --turbo instead of --turbopack. Check your Next.js version if you encounter an unrecognized flag error.

What Nextra Configures Automatically

When Turbopack is detected, Nextra automatically applies several configuration changes inside its withNextra() plugin so you do not have to configure them manually.

Automatic transpilePackages

When Turbopack is active (Next.js sets TURBOPACK=1 in Next.js 15 or TURBOPACK=auto in Next.js 16+), Nextra adds ESM-only packages to transpilePackages to prevent module resolution errors:
// Nextra adds these automatically when the TURBOPACK env var is set
transpilePackages: ['shiki', 'ts-morph']
This resolves a known issue where Turbopack cannot natively import certain ESM-only packages. See Next.js issue #63318 for background.

Turbopack loaders for MDX

Nextra registers custom Turbopack loaders that handle .md and .mdx file transformation. These are equivalent to the Webpack loaders Nextra registers when Turbopack is not used:
PatternLoader purpose
./{src/,}app/**/page.{md,mdx}Page-level MDX imports (full page transform)
*.{md,mdx}Partial/component MDX imports
**/nextra/dist/server/page-map/placeholder.jsPage map placeholder
**/nextra/dist/server/page-map/get.jsPage map data fetcher

resolveAlias entries

Nextra also adds Turbopack resolveAlias entries to fix module resolution for MDX and optional packages:
resolveAlias: {
  'next-mdx-import-source-file': '@vercel/turbopack-next/mdx-import-source',
  // Fixes: Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'
  '@theguild/remark-mermaid/mermaid': '...resolved path...',
  'private-next-root-dir/*': './*',
  'private-next-content-dir/*': './content/*'
}

Version-based Configuration Key

Turbopack configuration lives under different keys depending on the Next.js version. Nextra handles this automatically:
Nextra uses the top-level turbopack key in the Next.js config object:
next.config.mjs
// next.config.mjs — Next.js 16+ / Next.js 15.3+
// Nextra writes to nextConfig.turbopack automatically
export default withNextra({
  // your Next.js config
})
Nextra determines which key to use by reading the installed next package version at build time:
// Nextra internal logic (simplified)
const shouldUseConfigTurbopack =
  nextMajorVersion > 15 || (nextMajorVersion === 15 && nextMinorVersion > 2)
You do not need to configure this yourself — Nextra handles it transparently.

Serializable Options Only

Turbopack requires that all loader options be JSON-serializable. This means you cannot pass function-based plugin options — such as remarkPlugins, rehypePlugins, or recmaPlugins — when running next dev --turbopack.
Passing non-serializable plugin functions to nextra() while Turbopack is active will result in the following error:
Error: loader nextra/loader for match "./{src/app,app}/**/page.{md,mdx}"
does not have serializable options.
Ensure that options passed are plain JavaScript objects and values.
The following configuration works only with Webpack (i.e., next build or next dev without --turbopack):
next.config.mjs
import nextra from 'nextra'

// ❌ These function values cannot be passed when Turbopack is active
const withNextra = nextra({
  mdxOptions: {
    remarkPlugins: [myRemarkPlugin],
    rehypePlugins: [myRehypePlugin],
    recmaPlugins: [myRecmaPlugin]
  }
})

export default withNextra({})

Workaround: apply plugins in mdx-components.tsx

For plugins that transform MDX output, consider applying transformations at the component level in your mdx-components.tsx file, or use the next build path (which uses Webpack) for plugin-dependent builds.
Because next build does not yet support Turbopack, all production builds use Webpack and therefore do support function-based plugin options. The serialization constraint applies only to next dev --turbopack.

Summary

  • Registers .md and .mdx Turbopack loaders
  • Sets up resolveAlias for MDX and Mermaid modules
  • Adds shiki and ts-morph to transpilePackages when TURBOPACK=1 (Next.js 15) or TURBOPACK=auto (Next.js 16+) is set
  • Uses turbopack key (Next.js 16+) or experimental.turbo key (Next.js ≤ 15.2) automatically
  • Add --turbopack to your next dev script in package.json
  • Avoid passing function-based remark/rehype/recma plugins in nextra() options when using next dev --turbopack
CommandBundler
next devWebpack
next dev --turbopackTurbopack
next buildWebpack (always)
next startN/A (serves pre-built output)

Build docs developers (and LLMs) love