MinhVo

Minh Vo

rss feed

Slaying code & making it lit fr fr 🔥 tagline

Hey there 👋 I'm an AI Engineer with 7 years of experience building scalable web and mobile applications. Currently at Neurond AI (May 2025 — present), architecting an Enterprise AI Assistant Platform with multi-tenant RAG on pgvector, multi-provider LLM orchestration, and Azure-native infrastructure. Previously spent 5+ years at SNAPTEC (Sep 2019 — Apr 2025), leading SaaS themes, admin dashboards, and e-commerce platforms — earned the Hero of the Year award in 2021. I specialize in TypeScript, React, Next.js, and AI-Native engineering with Claude Code and Cursor.bio

Back to blogs

Next.js Turbopack: Rust-Powered Bundler

Explore Turbopack: architecture, benchmarks, and migration from webpack.

Next.jsTurbopackBundlerPerformance

By MinhVo

Introduction

Turbopack is Next.js's Rust-powered bundler, designed to replace webpack as the default build tool for Next.js applications. Built by the creators of Next.js at Vercel, Turbopack leverages Rust's performance characteristics to deliver dramatically faster build times — up to 10x faster than webpack for large applications and up to 700x faster than Vite for certain operations. It's the spiritual successor to webpack, built from the ground up to address the performance bottlenecks that have plagued JavaScript bundlers for years.

The need for a new bundler arose from fundamental limitations in webpack's architecture. Webpack processes modules sequentially and rebuilds entire dependency graphs on every change, which creates unacceptable delays in large codebases. Turbopack solves this through an incremental computation engine that only recomputes what changed, a function-level caching system that persists across builds, and parallelized processing that utilizes all available CPU cores. This guide covers Turbopack's architecture, benchmarks, migration path, and production deployment strategies.

Rust Performance Architecture

Understanding Turbopack: Core Concepts

Incremental Computation Engine

The core innovation of Turbopack is its incremental computation engine, called the Turbo engine. Unlike webpack, which rebuilds the entire dependency graph on every change, Turbopack tracks dependencies at the function level. When a file changes, the engine identifies exactly which functions are affected and recomputes only those functions, leaving the rest of the build output untouched.

This approach is inspired by build systems like Bazel and Buck, which use content-addressable storage and fine-grained dependency tracking to achieve near-instantaneous rebuilds. Turbopack brings these concepts to the JavaScript ecosystem, applying them to the unique challenges of bundling JavaScript, TypeScript, CSS, and static assets.

The Turbo engine uses a memoization cache that persists across builds. Each function's output is cached based on its inputs, so if a function's inputs haven't changed, the cached output is reused without recomputation. This cache is stored on disk, meaning even cold starts benefit from previous build computations.

Module Graph Processing

Turbopack processes the module graph differently from webpack. Instead of building a complete dependency graph and then optimizing it, Turbopack uses a lazy, demand-driven approach. It starts from entry points and only processes modules that are actually imported, avoiding the cost of analyzing unused code paths.

This lazy processing is particularly beneficial for development, where you typically work on a small subset of your application. Turbopack only bundles the code needed for the current page, ignoring the rest of the codebase until it's actually requested.

Turbopack vs. webpack Architecture

The architectural differences between Turbopack and webpack are fundamental:

  • webpack: JavaScript-based, sequential processing, full rebuilds on change, plugin-based architecture
  • Turbopack: Rust-based, parallel processing, incremental computation, native feature integration

webpack's plugin architecture, while flexible, introduces overhead. Each plugin must inspect and potentially modify the entire module graph, and plugins are executed sequentially. Turbopack moves common functionality (TypeScript compilation, CSS processing, asset handling) into native Rust code, eliminating the overhead of JavaScript plugin execution.

Bundler Architecture Comparison

Architecture and Design Patterns

The Rust Core

Turbopack's core is written in Rust, which provides several advantages over JavaScript:

  1. Zero-cost abstractions: Rust's type system and ownership model enable high-level abstractions without runtime overhead
  2. Fearless concurrency: Rust's ownership model prevents data races, enabling safe parallel processing
  3. Predictable performance: No garbage collector pauses, consistent memory usage
  4. Native speed: Direct compilation to machine code, no JavaScript runtime overhead

The Rust core handles module resolution, dependency tracking, code transformation, and bundle generation. JavaScript code is only used for configuration (next.config.js) and custom loaders, which are called through a well-defined bridge.

Node.js API Bridge

Turbopack provides a Node.js API for advanced use cases and tooling integration. This API allows you to programmatically create and run Turbopack builds:

import { createTurbopack } from 'turbo';
 
const turbopack = await createTurbopack({
  rootDir: process.cwd(),
  entrypoints: {
    main: './src/index.ts',
  },
  dev: true,
});
 
const { subscriptions } = await turbopack.watch();
 
for await (const event of subscriptions) {
  if (event.type === 'update') {
    console.log('Files changed:', event.paths);
    // Trigger HMR update
  }
}

Module Federation and Code Splitting

Turbopack supports automatic code splitting with a smarter algorithm than webpack. It analyzes import patterns and creates optimal chunk boundaries:

// Turbopack automatically creates separate chunks for:
// 1. Shared modules imported by multiple pages
// 2. Dynamic imports (lazy-loaded components)
// 3. Large dependencies (e.g., lodash, moment)
 
// Dynamic imports trigger automatic code splitting
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <Spinner />,
});
 
// Turbopack creates a separate chunk for this import
const utils = await import('./heavy-utils');

CSS and Asset Processing

Turbopack natively supports CSS Modules, PostCSS, and static asset processing without additional configuration:

// CSS Modules work out of the box
import styles from './Button.module.css';
 
export function Button({ children }) {
  return <button className={styles.button}>{children}</button>;
}
 
// Static assets are automatically processed
import logo from './logo.svg';
import heroImage from './hero.jpg';

Step-by-Step Implementation

Step 1: Enable Turbopack for Development

Turbopack is currently available as a development server. Enable it in your package.json:

{
  "scripts": {
    "dev": "next dev --turbo",
    "build": "next build",
    "start": "next start"
  }
}

Step 2: Verify Turbopack Compatibility

Check that your project's dependencies are compatible with Turbopack. Most standard Next.js configurations work out of the box, but some webpack-specific configurations may need adjustment.

# Start the development server with Turbopack
npm run dev
 
# Watch for any compatibility warnings in the terminal
# Common issues:
# - Custom webpack configurations (may need Turbopack equivalents)
# - Legacy loaders (may need replacement)
# - Non-standard import patterns

Step 3: Migrate Custom Webpack Configurations

If you have custom webpack configurations in next.config.js, migrate them to Turbopack equivalents:

// Before: webpack configuration
module.exports = {
  webpack: (config, { isServer }) => {
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    });
    
    config.resolve.alias['@components'] = path.join(__dirname, 'src/components');
    
    return config;
  },
};
 
// After: Turbopack configuration
module.exports = {
  turbopack: {
    rules: {
      '*.svg': {
        loaders: ['@svgr/webpack'],
        as: '*.js',
      },
    },
    resolveAlias: {
      '@components': './src/components',
    },
  },
};

Step 4: Benchmark Your Application

Compare build times between webpack and Turbopack:

# Benchmark webpack
time npm run build 2>&1 | tail -1
 
# Benchmark Turbopack development server
time npm run dev --turbo &
# Wait for server to start, then trigger a page load
curl http://localhost:3000
# Check terminal for compilation time

Step 5: Configure Production Build

While Turbopack is currently focused on development, production support is being developed. Prepare your configuration:

// next.config.js
const nextConfig = {
  // Turbopack configuration for development
  turbopack: {
    resolveAlias: {
      '@': './src',
    },
    resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
  },
  
  // webpack configuration for production (temporary)
  webpack: (config) => {
    config.resolve.alias['@'] = path.join(__dirname, 'src');
    return config;
  },
};
 
module.exports = nextConfig;

Migration Workflow

Real-World Use Cases

Use Case 1: Large Enterprise Applications

Enterprise applications with thousands of components and complex dependency graphs benefit the most from Turbopack. A typical enterprise Next.js app with 5,000+ components might take 30-60 seconds to compile with webpack. Turbopack reduces this to 2-5 seconds, enabling near-instant hot module replacement and dramatically improving developer productivity.

The incremental computation engine is particularly valuable here. When a developer modifies a single component, Turbopack only recomputes the affected functions, while webpack would recompile the entire component tree. This difference is negligible for small projects but transformative for large ones.

Use Case 2: Monorepo Development

Monorepos with multiple Next.js applications share dependencies and configuration. Turbopack's function-level caching works across packages, so changes to shared libraries only trigger recomputation in the specific functions that use them. This eliminates the "full rebuild" problem that plagues monorepo development with webpack.

Use Case 3: Design System Development

Design systems with hundreds of components need fast iteration cycles. Turbopack's near-instant HMR allows designers and developers to see changes in under 100ms, creating a fluid development experience similar to editing static HTML. This speed encourages experimentation and reduces the friction of component development.

Best Practices for Production

  1. Start with Development: Enable Turbopack for development (next dev --turbo) while keeping webpack for production builds until Turbopack production support is stable.

  2. Audit Custom Webpack Configs: Review all custom webpack configurations and identify which ones have Turbopack equivalents. Some configurations may need to be rewritten.

  3. Test CSS Modules and PostCSS: Turbopack handles CSS differently from webpack. Verify that your CSS Modules, PostCSS plugins, and Tailwind CSS configurations work correctly.

  4. Monitor Compilation Times: Use Turbopack's built-in profiling to identify slow modules. The --turbopack-profile flag generates detailed performance reports.

  5. Update Dependencies: Ensure all dependencies are compatible with Turbopack. Some older packages may rely on webpack-specific features that aren't available.

  6. Use Standard Import Patterns: Avoid webpack-specific require() patterns and use standard ES module imports. Turbopack optimizes for standard import patterns.

  7. Leverage Automatic Code Splitting: Trust Turbopack's code splitting algorithm. Manual chunk configuration (common in webpack) is usually unnecessary and can prevent optimal splitting.

  8. Report Issues: Turbopack is still in development. If you encounter issues, report them to the Next.js team with a minimal reproduction.

Common Pitfalls and Solutions

PitfallImpactSolution
Custom webpack plugins not supportedBuild failuresFind Turbopack equivalents or refactor to standard patterns
CSS preprocessing issuesStyles not appliedVerify PostCSS and CSS Modules configuration
Dynamic require() not supportedRuntime errorsConvert to ES module imports
Missing Turbopack configurationAlias/resolve issuesAdd turbopack config alongside webpack config
Production build not availableCan't use Turbopack in productionUse Turbopack for dev, webpack for production
Large dependency analysisSlow initial compilationUse transpilePackages for problematic packages

Performance Optimization

Benchmarking Turbopack Performance

# Enable Turbopack profiling
next dev --turbo --turbopack-profile
 
# This generates a .cpuprofile file that can be analyzed in Chrome DevTools
# Open chrome://inspect -> Open dedicated DevTools for Node -> Load profile

Optimizing Module Resolution

// next.config.js
module.exports = {
  turbopack: {
    resolveAlias: {
      // Pre-resolve common imports to reduce module resolution time
      '@components': './src/components',
      '@utils': './src/utils',
      '@hooks': './src/hooks',
    },
    resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
    rules: {
      // Exclude large files from bundling
      '*.md': {
        loaders: ['raw-loader'],
        as: '*.js',
      },
    },
  },
};

Reducing Initial Compilation Time

// Use specific imports instead of barrel exports
// ❌ Bad: imports everything from the barrel file
import { Button, Card, Modal, Table } from '@/components';
 
// ✅ Good: imports specific components
import { Button } from '@/components/Button';
import { Card } from '@/components/Card';
import { Modal } from '@/components/Modal';
import { Table } from '@/components/Table';

Comparison with Alternatives

FeatureTurbopackwebpackViteesbuild
LanguageRustJavaScriptJavaScript/RustGo
Dev Server SpeedFastestSlowFastFast
Incremental BuildsFunction-levelModule-levelModule-levelFile-level
Cold StartFast (persistent cache)SlowFastFast
HMR SpeedSub-50ms100-500ms50-100msN/A
Production BuildsComing soonFull supportFull supportPartial
Next.js IntegrationNativeNativeManualManual
Code SplittingAutomaticManual configAutomaticManual

Advanced Patterns

Custom Turbopack Loaders

Create custom loaders for Turbopack:

// next.config.js
module.exports = {
  turbopack: {
    rules: {
      '*.md': {
        loaders: [
          {
            loader: '@next/mdx-loader',
            options: {
              remarkPlugins: [remarkGfm],
              rehypePlugins: [rehypeHighlight],
            },
          },
        ],
        as: '*.js',
      },
      '*.graphql': {
        loaders: ['graphql-tag/loader'],
        as: '*.js',
      },
    },
  },
};

Turbopack with Monorepos

Configure Turbopack for monorepo development:

// next.config.js
module.exports = {
  turbopack: {
    resolveAlias: {
      // Map monorepo packages to their source directories
      '@monorepo/ui': '../../packages/ui/src',
      '@monorepo/utils': '../../packages/utils/src',
    },
  },
  // Transpile monorepo packages
  transpilePackages: ['@monorepo/ui', '@monorepo/utils'],
};

Turbopack with Environment Variables

// next.config.js
module.exports = {
  turbopack: {
    define: {
      // Define environment variables for Turbopack
      'process.env.NEXT_PUBLIC_API_URL': JSON.stringify(process.env.NEXT_PUBLIC_API_URL),
      'process.env.NEXT_PUBLIC_APP_VERSION': JSON.stringify(require('./package.json').version),
    },
  },
};

Testing Strategies

// turbopack-compatibility.test.ts
import { execSync } from 'child_process';
import http from 'http';
 
describe('Turbopack Compatibility', () => {
  let serverProcess: any;
 
  beforeAll(async () => {
    // Start Turbopack dev server
    serverProcess = execSync('next dev --turbo --port 3001', {
      cwd: process.cwd(),
      timeout: 30000,
    });
  });
 
  afterAll(() => {
    serverProcess?.kill();
  });
 
  it('compiles all pages without errors', async () => {
    const pages = ['/', '/about', '/blog', '/contact'];
    
    for (const page of pages) {
      const response = await fetch(`http://localhost:3001${page}`);
      expect(response.status).toBe(200);
    }
  });
 
  it('supports CSS Modules', async () => {
    const response = await fetch('http://localhost:3001/');
    const html = await response.text();
    
    // Verify CSS is applied (check for CSS class names)
    expect(html).toMatch(/class="[^"]*"/);
  });
 
  it('handles dynamic imports', async () => {
    const response = await fetch('http://localhost:3001/dashboard');
    expect(response.status).toBe(200);
  });
});

Future Outlook

Turbopack is rapidly evolving toward production readiness. The roadmap includes:

  • Production Builds: Turbopack for next build is in active development, with early benchmarks showing 5-10x improvements over webpack
  • Persistent Caching: Cross-build caching that persists compilation results, making subsequent builds near-instantaneous
  • Module Federation: Native support for micro-frontend architectures with optimized chunk sharing
  • Custom Plugins: A plugin system that maintains Rust-level performance while allowing extensibility

The long-term vision is to make Turbopack the default bundler for all Next.js applications, replacing webpack entirely. This transition will be gradual, with webpack support maintained for backward compatibility until Turbopack achieves feature parity.

Turbopack Performance Benchmarks

Turbopack's Rust-based architecture delivers significant performance improvements over Webpack for large Next.js applications. In benchmarks with 3,000-module applications, Turbopack achieves cold starts in under 400ms compared to Webpack's 3-5 seconds. Hot module replacement with Turbopack completes in under 10ms for most changes, regardless of application size. The incremental computation engine only recomputes the affected modules and their dependents, avoiding the full rebuild that Webpack performs. Memory usage is also lower because Turbopack's Rust runtime has more efficient memory management than Node.js-based bundlers.

Migrating from Webpack to Turbopack

The migration from webpack to Turbopack in Next.js is designed to be incremental. Enable Turbopack for development by running next dev --turbopack and verify that your application functions correctly. Most webpack configurations in next.config.js work with Turbopack without modification because Turbopack understands the same configuration schema. However, custom webpack plugins that hook into internal webpack APIs may not be compatible and will need Turbopack-specific alternatives.

For applications using custom webpack loaders, verify that Turbopack supports the loader or provides an equivalent built-in transform. Common loaders like css-loader, style-loader, and file-loader are handled natively by Turbopack. Custom loaders that transform specific file types may need to be reimplemented as Turbopack plugins. The Turbopack team provides a compatibility guide that lists supported and unsupported webpack features.

Test your application thoroughly after enabling Turbopack, paying special attention to CSS module resolution, environment variable access, and dynamic imports. These areas have subtle behavioral differences between webpack and Turbopack that may require configuration adjustments. Run your full test suite and verify that production builds produce equivalent output before making Turbopack the default for your team.

Conclusion

Turbopack represents the next generation of JavaScript bundling, bringing Rust's performance advantages to the Next.js ecosystem. Its incremental computation engine, function-level caching, and parallelized processing deliver transformative speed improvements for development workflows.

Key takeaways:

  1. Turbopack is up to 10x faster than webpack for large applications, with sub-50ms HMR
  2. Enable it for development with next dev --turbo while keeping webpack for production builds
  3. Migrate custom webpack configurations to Turbopack equivalents using the turbopack config key
  4. Leverage automatic code splitting and native CSS/asset processing for optimal performance
  5. Monitor the production build roadmap and prepare your codebase for the transition

For developers working on large Next.js applications, Turbopack is not just an optimization — it's a fundamental improvement to the development experience. The seconds saved on every code change compound into hours of productive time recovered each week.

For the latest updates, see the Turbopack documentation and the Next.js Turbopack guide.