0Pricing
Next.js 15 Fullstack (App Router + Server Actions) · 강의

Turbopack과 컴파일러 설정 심층 분석

더 빠른 빌드와 더 작은 출력을 위해 Turbopack, 변환 및 SWC 기반 컴파일러를 조정하는 방법을 배웁니다.

Turbopack과 컴파일러 설정 심층 분석은(는) CoddyKit의 무료 Next.js 15 Fullstack (App Router + Server Actions) 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Next.js 15 Fullstack (App Router + Server Actions) 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Next.js 15 Fullstack (App Router + Server Actions) 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Why Turbopack Exists

Next.js 15 ships Turbopack as the default bundler for next dev. It was built in Rust to replace the JavaScript-based Webpack pipeline that powered Next.js for years.

The core problem Webpack faced at scale: every file change triggered a JavaScript graph traversal and re-evaluation. At 10,000 modules, a single edit could take 8–15 seconds before HMR landed in the browser.

Turbopack solves this with three architectural bets:

  • Incremental computation — only the modules affected by a change are re-evaluated, not the whole graph.
  • Parallel compilation — Rust's fearless concurrency lets multiple CPU cores transform files simultaneously.
  • Persistent caching — transform results are stored on disk and survive process restarts.

The result: cold start times drop by roughly 50–75% on large apps, and HMR latency falls to single-digit milliseconds in most cases.

Enabling Turbopack in next.config.ts

In Next.js 15, next dev --turbopack is the recommended way to opt in during development. For production builds, Webpack remains the default until Turbopack reaches full parity, so you control the flag per command in package.json.

You can also embed Turbopack options directly inside next.config.ts under the experimental.turbo key (renamed to turbopack in the stable API).

Key points to keep in mind:

  • The turbopack key only affects next dev; production builds still use Webpack unless you pass --turbopack to next build (experimental in v15).
  • Options in turbopack are merged on top of Turbopack's built-in defaults — you never have to replicate the full config.
  • The TypeScript config file (next.config.ts) gives you full type safety for these options via the NextConfig type.
// next.config.ts
import type { NextConfig } from 'next';

const config: NextConfig = {
  turbopack: {
    // Turbopack-specific options go here
    // (rules, resolveAlias, resolveExtensions, etc.)
  },
};

export default config;

Turbopack Loaders: Replacing Webpack Rules

Webpack used module.rules with loaders like babel-loader or raw-loader. Turbopack has an equivalent called rules inside the turbopack config block.

Each rule maps a file-extension glob to one or more Turbopack-compatible loaders. Note that Webpack loaders are not directly compatible — Turbopack requires loaders that implement its own transform API, though many popular loaders (e.g. @svgr/webpack, @mdx-js/loader) have published Turbopack-compatible versions.

Anatomy of a rule:

  • test — a glob or regex string matching file paths
  • use — an array of loader objects, each with a loader package name and an optional options object

Loaders run right-to-left, exactly as in Webpack.

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

const config: NextConfig = {
  turbopack: {
    rules: {
      // Transform .svg files into React components
      '*.svg': {
        loaders: ['@svgr/webpack'],
        as: '*.js',
      },
      // Transform raw .txt files into string modules
      '*.txt': {
        loaders: ['raw-loader'],
        as: '*.js',
      },
    },
  },
};

export default config;

Module Aliases with resolveAlias

Path aliases let you write import { Button } from '@ui/Button' instead of ../../components/ui/Button. Turbopack supports this via turbopack.resolveAlias, which mirrors Webpack's resolve.alias.

You should also keep your tsconfig.json paths in sync — the TypeScript compiler uses paths for type checking, while Turbopack uses resolveAlias for bundling. A mismatch causes "module not found" errors at build time even though types look correct in your editor.

Common pattern: define the canonical mapping in one place and derive both configs from it, or use next/jest which auto-reads tsconfig.json paths for Jest.

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

const config: NextConfig = {
  turbopack: {
    resolveAlias: {
      '@ui': path.resolve(__dirname, 'src/components/ui'),
      '@lib': path.resolve(__dirname, 'src/lib'),
      '@server': path.resolve(__dirname, 'src/server'),
    },
  },
};

export default config;

// tsconfig.json (keep in sync)
// {
//   "compilerOptions": {
//     "paths": {
//       "@ui/*": ["./src/components/ui/*"],
//       "@lib/*": ["./src/lib/*"],
//       "@server/*": ["./src/server/*"]
//     }
//   }
// }

SWC: Next.js's Built-in Compiler

Alongside Turbopack, Next.js uses SWC (Speedy Web Compiler) as its code transformer. SWC is also written in Rust and handles TypeScript stripping, JSX transformation, minification, and optional syntax transforms.

Important distinction:

  • Turbopack is the bundler — it builds the module graph, resolves imports, and orchestrates code splitting.
  • SWC is the transformer — it converts individual files (TS → JS, JSX → React.createElement calls, etc.).

Both are active by default in Next.js 15. SWC replaces Babel for most projects; if you still have a .babelrc in your repo, Next.js will fall back to Babel and disable SWC — this is a common source of slow builds on migrated projects.

To confirm SWC is active, run next build and look for "SWC minify" in the output.

Configuring SWC Transforms in next.config.ts

SWC transforms are configured at the top level of NextConfig (not inside turbopack). The most commonly tuned options are:

  • compiler.styledComponents — enables the SWC plugin for styled-components, adding display names and deterministic class names.
  • compiler.emotion — same for the Emotion CSS-in-JS library.
  • compiler.removeConsole — strips console.* calls from production builds. You can whitelist specific methods (e.g. keep console.error).
  • compiler.reactRemoveProperties — removes custom React props (like data-testid) from production output, reducing HTML payload.

These transforms run on every file during compilation, so enabling only what you need keeps build times tight.

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

const isProd = process.env.NODE_ENV === 'production';

const config: NextConfig = {
  compiler: {
    // Remove console.log but keep console.error in production
    removeConsole: isProd
      ? { exclude: ['error', 'warn'] }
      : false,

    // Strip data-testid attributes from JSX in production
    reactRemoveProperties: isProd
      ? { properties: ['^data-testid$'] }
      : false,

    // Enable styled-components SWC plugin
    styledComponents: true,
  },
};

export default config;

SWC Minification vs Terser

Next.js 15 uses SWC for minification by default (swcMinify: true is now the implicit default). This replaces Terser, the JavaScript-based minifier that was standard for years.

Benchmark comparison on a medium Next.js app (~300 modules):

  • Terser: ~18 seconds minification during next build
  • SWC minifier: ~3 seconds — roughly 6× faster

SWC minification is also scope-aware and performs dead-code elimination (DCE) at the module level. Combined with tree-shaking from the bundler, this means unused exports that Terser might have kept can be eliminated.

If you encounter an edge case where SWC minification produces incorrect output (rare but possible), you can opt back to Terser:

// next.config.ts — only needed if SWC minifier causes issues
import type { NextConfig } from 'next';

const config: NextConfig = {
  // Explicitly disable SWC minification and fall back to Terser
  swcMinify: false,
};

export default config;

// Alternatively, to tune SWC minification behavior:
// (no direct config exposed yet — SWC minifier config is internal)
// The recommended approach is to leave swcMinify: true (default)
// and report any correctness bugs to the Next.js GitHub repo.

Bundle Analyzer: Visualizing What You Ship

Before optimizing bundle size, you need to see it. The @next/bundle-analyzer package wraps webpack-bundle-analyzer and integrates it with Next.js builds.

After setup, running ANALYZE=true next build opens an interactive treemap in your browser showing every module and its contribution to each JS chunk.

What to look for:

  • Large node_modules — e.g. moment.js (>70 KB gzipped) when you only need date formatting. Replace with date-fns or native Intl.DateTimeFormat.
  • Duplicate packages — two versions of react or lodash appearing in the treemap signals a resolution conflict.
  • Server vs Client chunks — code that belongs on the server leaking into the client bundle (e.g. a DB client).

Note: bundle-analyzer currently works with the Webpack build (next build without --turbopack). A Turbopack-native analyzer is on the roadmap.

// next.config.ts
import type { NextConfig } from 'next';
import bundleAnalyzer from '@next/bundle-analyzer';

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === 'true',
  openAnalyzer: true,
});

const config: NextConfig = {
  // ... your other config
};

export default withBundleAnalyzer(config);

// package.json script:
// "analyze": "ANALYZE=true next build"

Turbopack Persistent Cache Configuration

Turbopack's persistent cache stores transform and bundling artifacts in .next/cache/turbopack. On a second next dev run (or in CI after cache restoration), Turbopack reads from disk instead of recomputing — dramatically reducing cold-start time for CI pipelines.

Key behaviors to understand:

  • The cache is content-addressed: a file's cache key is a hash of its content plus the content of all its dependencies. You will never get a stale cache hit.
  • The cache directory can grow large over time. next dev has a built-in LRU eviction policy, but you can wipe it manually with rm -rf .next/cache/turbopack.
  • In CI, cache the .next/cache directory between runs. GitHub Actions example:
# .github/workflows/ci.yml (relevant excerpt)
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Restore Next.js cache
        uses: actions/cache@v4
        with:
          path: |
            ~/.npm
            ${{ github.workspace }}/.next/cache
          key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts','**/*.tsx') }}
          restore-keys: |
            ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-

      - run: npm ci
      - run: npm run build

Controlling Code Splitting and Chunk Strategy

Next.js automatically code-splits at the route level (each page gets its own JS chunk), but you can further influence splitting with two techniques:

1. Dynamic imports (next/dynamic) — lazily load heavy components so they are excluded from the initial page bundle. This is the primary tool for reducing First Load JS.

2. optimizePackageImports — a Next.js 15 config option that tells the compiler to tree-shake specific packages that don't have proper ESM exports. Libraries like lucide-react, @radix-ui/*, and icon packs often benefit from this.

Both techniques work with Turbopack and Webpack. optimizePackageImports is especially powerful because it requires zero changes to your import statements — it's purely a bundler hint.

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

const config: NextConfig = {
  // Tell the compiler to tree-shake these packages
  // even if they lack proper ESM export maps
  experimental: {
    optimizePackageImports: [
      'lucide-react',
      '@radix-ui/react-icons',
      'recharts',
      '@heroicons/react',
    ],
  },
};

export default config;

// In your component — no change needed:
// import { ChevronRight, User } from 'lucide-react';
// Only ChevronRight and User are bundled, not the full icon library.

Measuring Build Performance with next build --profile

When build times spike unexpectedly, Next.js provides built-in profiling to pinpoint bottlenecks. Two flags are most useful:

  • next build --profile — emits a React profiler trace and a .cpuprofile file you can open in Chrome DevTools to see which transforms or plugins are consuming time.
  • NEXT_TELEMETRY_DEBUG=1 next build — prints detailed timing breakdowns per phase (compilation, type checking, static generation, etc.) to stdout.

For Turbopack specifically, the --turbopack flag surfaces compile times per route segment in the terminal output. A single route taking disproportionately long often indicates a missing resolveAlias causing Turbopack to traverse a deep relative path on every HMR cycle.

Practical workflow: run with profiling → identify the slowest phase → apply the relevant config change → re-measure. Never guess at optimizations on a complex bundler.

// scripts/build-perf.ts — a small helper to time build phases
// Run with: npx ts-node scripts/build-perf.ts

import { execSync } from 'child_process';

function timed(label: string, cmd: string): void {
  const start = Date.now();
  console.log(`\n>>> Starting: ${label}`);
  try {
    execSync(cmd, { stdio: 'inherit', env: { ...process.env } });
  } catch {
    console.error(`[FAILED] ${label}`);
    process.exit(1);
  }
  const elapsed = ((Date.now() - start) / 1000).toFixed(2);
  console.log(`<<< Done: ${label} in ${elapsed}s`);
}

timed('Type check', 'npx tsc --noEmit');
timed('Next.js build', 'npx next build');

Knowledge Check: Turbopack Loaders vs Webpack Loaders

Test your understanding of the key difference between Turbopack's loader system and Webpack's loader system in Next.js 15.

Lesson Recap: Turbopack and Compiler Configuration

In this lesson you explored the full compiler and bundler configuration stack in Next.js 15:

  • Turbopack architecture — incremental computation, parallel Rust workers, and persistent disk caching make it dramatically faster than Webpack for development workflows.
  • turbopack config block — use rules for file-level transforms, resolveAlias for module path shortcuts, and keep tsconfig.json paths in sync to avoid type/bundle mismatches.
  • SWC as the transformer — distinct from Turbopack (the bundler), SWC handles TS stripping, JSX, and minification. A .babelrc in your project silently disables SWC.
  • compiler options — removeConsole, reactRemoveProperties, and CSS-in-JS plugins are configured at the top-level compiler key, not inside turbopack.
  • Bundle analysis — use @next/bundle-analyzer to visualize chunk composition and catch large dependencies or server-code leaking into client bundles.
  • optimizePackageImports — a zero-touch hint that enables tree-shaking for packages with poor ESM export maps.
  • CI caching — cache .next/cache between runs to leverage Turbopack's persistent cache and cut CI build times significantly.

The key mental model: Turbopack owns the graph, SWC owns the files, and next.config.ts is the single control plane for both.

자주 묻는 질문

“Turbopack과 컴파일러 설정 심층 분석” 강의는 무료인가요?

네 — “Turbopack과 컴파일러 설정 심층 분석” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Next.js 15 Fullstack (App Router + Server Actions) 강의 전체를 잠금 해제할 수 있습니다. Next.js 15 Fullstack (App Router + Server Actions) 강의에는 총 4개의 강의가 포함되어 있습니다.

“Turbopack과 컴파일러 설정 심층 분석”에서 뭘 배우나요?

더 빠른 빌드와 더 작은 출력을 위해 Turbopack, 변환 및 SWC 기반 컴파일러를 조정하는 방법을 배웁니다. 브라우저에서 직접 실행하는 실습 코드로 Next.js 15 Fullstack (App Router + Server Actions)을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Next.js 15 Fullstack (App Router + Server Actions)을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Next.js 15 Fullstack (App Router + Server Actions)은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“Turbopack과 컴파일러 설정 심층 분석” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Next.js 15 Fullstack (App Router + Server Actions) 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Next.js 15 Fullstack (App Router + Server Actions) 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 클라이언트 번들 분석과 축소
  2. Turbopack과 컴파일러 설정 심층 분석
  3. server-only와 client-only를 활용한 모듈 경계
  4. 동적 가져오기, 코드 분할과 지연 하이드레이션
← Next.js 15 Fullstack (App Router + Server Actions)(으)로 돌아가기