Documents
Home>Documents>Dev>Frontend

Next.js Turbopack 정리하기

12 min readMay 22, 2026May 22, 2026

Next.js Turbopack 정리하기

Next.js를 쓰다 보면 개발 서버를 켤 때 next dev --turbo 또는 next dev --turbopack 같은 옵션을 보게 된다. 여기서 Turbopack은 Next.js 개발 환경을 더 빠르게 만들기 위해 도입된 번들러다.

번들러라는 말부터 어렵게 느껴질 수 있다. 간단히 말하면, 개발자가 작성한 여러 JavaScript, TypeScript, CSS 파일을 브라우저가 이해하고 실행할 수 있는 형태로 묶어 주는 도구다. Next.js는 기존에 Webpack을 많이 사용해 왔고, Turbopack은 그 작업을 더 빠르게 처리하기 위해 만들어진 새로운 선택지다.

코드 에디터에서 Next.js 프로젝트를 개발하는 화면
코드 에디터에서 Next.js 프로젝트를 개발하는 화면

Next.js 개발 서버와 번들러는 코드 수정 후 브라우저 반영까지의 흐름에 관여한다.

이 글에서는 Turbopack을 처음 보는 사람이 이해할 수 있도록 기본 개념부터 정리한다. 그 다음 실제 개발에서 자주 만나는 Docker 컨테이너와 볼륨 바인드 문제, 파일 변경 감지 문제, 아직 주의해야 할 호환성 문제까지 함께 정리한다.

Turbopack은 무엇인가

Turbopack은 Vercel이 만든 Rust 기반의 번들러다. Next.js 문서에서는 Turbopack을 JavaScript와 TypeScript에 최적화된 증분 번들러라고 설명한다.

여기서 중요한 단어는 증분이다. 전체를 매번 처음부터 다시 처리하는 방식이 아니라, 바뀐 부분을 중심으로 필요한 작업만 다시 계산하는 방식에 가깝다. 개발 중에는 파일 하나를 고치고 브라우저에서 바로 결과를 확인하는 일이 반복된다. Turbopack은 이 반복 작업을 빠르게 만드는 데 초점이 있다.

기존 번들러가 나쁘다는 뜻은 아니다. Webpack은 오랫동안 널리 쓰였고 생태계도 크다. 다만 프로젝트가 커질수록 개발 서버 시작 시간이나 코드 수정 후 반영 시간이 길어질 수 있다. Turbopack은 이 지점을 개선하려고 나온 도구다.

번들러를 아주 단순하게 이해하기

프론트엔드 프로젝트에는 파일이 많다. 예를 들어 page.tsx, layout.tsx, button.tsx, style.css, 이미지 파일, 폰트 파일이 각각 따로 존재한다.

브라우저는 이 파일들을 그대로 모두 알아서 연결해 주지 않는다. 개발 도구가 파일 사이의 관계를 읽고, 필요한 순서대로 묶고, 개발 서버가 브라우저에 전달할 수 있는 형태로 준비해야 한다. 이 일을 하는 대표 도구가 번들러다.

여러 JavaScript 모듈이 번들러를 통해 하나의 결과물로 묶이는 개념도
여러 JavaScript 모듈이 번들러를 통해 하나의 결과물로 묶이는 개념도

번들러는 여러 파일의 관계를 읽고 브라우저가 실행할 수 있는 형태로 준비한다.

정리하면 번들러는 다음 일을 한다.

  • 여러 파일의 연결 관계를 파악한다.
  • TypeScript나 JSX처럼 변환이 필요한 코드를 처리한다.
  • CSS와 이미지 같은 자원도 함께 다룬다.
  • 브라우저가 실행할 수 있는 결과물을 만든다.
  • 개발 중 파일이 바뀌면 다시 반영한다.

Turbopack은 이 작업 중 특히 개발 중 반복되는 반영 과정을 빠르게 만들려는 목적이 강하다.

Turbopack을 켜는 방법

Next.js에서 Turbopack은 개발 서버를 실행할 때 옵션으로 켤 수 있다. Next.js CLI 문서next dev에서 --turbo 옵션을 제공한다고 설명한다.

가장 단순한 실행 방식은 다음과 같다.

next dev --turbo

package.json에 스크립트로 넣으면 매번 옵션을 직접 입력하지 않아도 된다.

{
  "scripts": {
    "dev": "next dev --turbo"
  }
}

이후에는 다음 명령으로 실행한다.

npm run dev

프로젝트에서 pnpm을 쓴다면 다음처럼 적을 수 있다.

{
  "scripts": {
    "dev": "next dev --turbo"
  }
}
pnpm dev

옵션 이름은 Next.js 버전에 따라 --turbo 또는 --turbopack 형태로 안내되는 경우가 있다. 프로젝트에서 사용하는 Next.js 버전의 CLI 도움말을 기준으로 맞추면 된다.

Turbopack이 빠르게 느껴지는 이유

Turbopack이 빠르게 느껴지는 이유는 단순히 Rust로 만들었기 때문만은 아니다. Rust는 성능에 유리한 언어지만, 언어 하나만으로 개발 서버가 빨라지는 것은 아니다.

핵심은 바뀐 부분만 다시 처리하려는 구조다. 파일 하나를 수정했을 때 전체 프로젝트를 다시 읽고 다시 묶는 대신, 변경된 파일과 그 파일에 영향을 받는 범위를 중심으로 작업한다. 프로젝트가 커질수록 이 차이가 체감될 수 있다.

또한 개발 서버에서는 완성된 배포 파일을 만드는 것보다 빠른 피드백이 더 중요하다. 개발자가 코드를 바꾸고 브라우저에서 결과를 확인하는 시간이 짧아지면 작업 흐름이 덜 끊긴다. Turbopack은 이 개발 단계의 피드백 시간을 줄이는 방향으로 설계되어 있다.

Webpack과 Turbopack의 차이

Webpack과 Turbopack을 비교할 때 가장 쉽게 볼 수 있는 차이는 목적과 설계 시점이다.

Webpack은 오래된 생태계를 가진 범용 번들러다. 다양한 플러그인과 로더가 있고, 많은 프레임워크와 라이브러리에서 사용해 왔다. 복잡한 설정을 통해 거의 모든 형태의 프론트엔드 빌드를 처리할 수 있다.

Turbopack은 Next.js와 현대적인 JavaScript, TypeScript 개발 경험을 더 빠르게 만들기 위해 만들어졌다. 기존 Webpack 설정과 완전히 같은 방식으로 확장되는 도구는 아니다. 그래서 속도 면에서는 장점이 있지만, Webpack 플러그인에 의존하는 프로젝트에서는 바로 바꾸기 어려울 수 있다.

Webpack과 Turbopack 빌드 시간 비교 차트
Webpack과 Turbopack 빌드 시간 비교 차트

Turbopack은 Webpack과 다른 구조로 빠른 개발 피드백을 목표로 한다.

간단히 정리하면 다음과 같다.

  • Webpack은 성숙한 생태계와 높은 호환성이 강점이다.
  • Turbopack은 Next.js 개발 서버의 빠른 피드백에 초점이 있다.
  • Webpack 설정을 많이 건드린 프로젝트는 Turbopack 전환 전에 확인이 필요하다.
  • 새 프로젝트나 설정이 단순한 프로젝트는 Turbopack을 비교적 쉽게 시험해 볼 수 있다.

Turbopack을 쓰면 모든 것이 해결되는 것은 아니다

Turbopack은 개발 서버를 빠르게 만들 수 있지만, 모든 프로젝트에서 항상 문제 없이 동작한다고 보는 것은 위험하다. 특히 기존 Webpack 설정, 커스텀 로더, 특수한 모듈 처리 방식에 의존하는 프로젝트라면 차이가 생길 수 있다.

Next.js 문서의 Turbopack 지원 기능 안내는 Webpack과 Turbopack의 차이를 따로 설명한다. 이 차이는 실제 프로젝트에서 중요하다. 개발 서버는 빨라졌는데 특정 패키지나 CSS 처리 방식이 다르게 동작하면, 결국 디버깅 시간이 늘어날 수 있기 때문이다.

초보자 입장에서는 다음 기준으로 접근하는 편이 안전하다.

  • 새 프로젝트라면 Turbopack을 켜고 시작해 본다.
  • 기존 프로젝트라면 먼저 브랜치를 나누고 테스트한다.
  • Webpack 설정을 직접 많이 수정했다면 바로 전환하지 않는다.
  • 문제가 생기면 Webpack 개발 서버로 되돌릴 수 있게 스크립트를 분리한다.

예를 들어 package.json에 두 스크립트를 함께 둘 수 있다.

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

이렇게 해 두면 Turbopack에서 문제가 생겼을 때 바로 비교할 수 있다.

Docker에서 Turbopack을 쓸 때 왜 문제가 생기는가

Docker 컨테이너 안에서 Next.js 개발 서버를 띄우는 경우가 있다. 이때 보통 로컬 소스 코드를 컨테이너 안으로 연결하기 위해 볼륨 바인드를 사용한다.

Docker bind mount는 호스트 컴퓨터의 특정 디렉터리를 컨테이너 내부 경로에 연결하는 방식이다. 예를 들어 내 컴퓨터의 프로젝트 폴더를 컨테이너의 /app에 연결하면, 컨테이너 안에서도 같은 파일을 보는 것처럼 사용할 수 있다.

문제는 개발 서버가 파일 변경을 감지하는 방식이다. Turbopack이나 Webpack 같은 개발 도구는 파일이 바뀌었는지 계속 감시한다. 그런데 Docker Desktop 환경, 특히 macOS나 Windows에서는 호스트 파일 시스템과 Linux 컨테이너 파일 시스템 사이에 경계가 있다. 이 경계 때문에 파일 변경 이벤트가 느리게 전달되거나, 기대한 방식으로 감지되지 않는 경우가 있다.

Docker bind mount가 호스트 디렉터리를 컨테이너에 연결하는 구조도
Docker bind mount가 호스트 디렉터리를 컨테이너에 연결하는 구조도

Docker bind mount는 호스트 파일을 컨테이너 내부 경로에 연결한다.

초보자에게는 이 현상이 특히 어렵다. 코드를 분명히 수정했는데 브라우저에 반영되지 않거나, 개발 서버를 껐다 켜야 반영되거나, 반대로 CPU 사용량이 높아지는 식으로 나타날 수 있다.

Docker 볼륨 바인드에서 자주 보이는 증상

Docker와 Turbopack을 함께 사용할 때 나타날 수 있는 증상은 대체로 파일 변경 감지와 관련이 있다.

대표적인 증상은 다음과 같다.

  • 파일을 수정했는데 화면이 바로 갱신되지 않는다.
  • 저장 후 몇 초 뒤에야 반영된다.
  • 새 파일을 만들었는데 라우트나 컴포넌트가 인식되지 않는다.
  • 컨테이너 안에서 개발 서버를 재시작해야만 반영된다.
  • node_modules까지 호스트 볼륨과 섞이면서 의존성 문제가 생긴다.
  • macOS나 Windows에서 Linux 컨테이너를 쓸 때 체감 속도가 크게 떨어진다.

이 문제는 Turbopack만의 문제라고 단정하기 어렵다. Docker bind mount 자체의 특성, 운영체제 차이, 파일 감시 방식, Next.js 버전, 프로젝트 구조가 함께 영향을 준다.

가장 흔한 원인: node_modules를 잘못 마운트하는 경우

Docker 개발 환경에서 가장 흔한 실수 중 하나는 프로젝트 전체를 컨테이너에 마운트하면서 node_modules 처리까지 꼬이는 경우다.

예를 들어 다음과 같은 설정은 겉으로 보기에는 자연스럽다.

services:
  app:
    volumes:
      - .:/app

하지만 이 방식은 호스트의 프로젝트 폴더 전체를 컨테이너의 /app에 덮어쓴다. 이미지 빌드 단계에서 컨테이너 안에 설치해 둔 node_modules가 있더라도, 볼륨이 /app 전체를 덮으면 의도와 다르게 보일 수 있다.

보통은 node_modules를 별도 볼륨으로 분리하는 방식을 많이 쓴다.

services:
  app:
    volumes:
      - .:/app
      - /app/node_modules

이 설정은 소스 코드는 호스트와 연결하고, 컨테이너 내부의 node_modules는 별도로 유지하려는 의도다. 프로젝트와 패키지 매니저에 따라 더 세밀한 조정이 필요할 수 있지만, 초보자가 처음 확인할 부분은 이 지점이다.

Turbopack과 파일 감시 문제

개발 서버는 파일 변경을 감지해야 한다. 일반적인 로컬 환경에서는 파일 시스템 이벤트를 받아서 빠르게 반응한다. 하지만 Docker bind mount 환경에서는 이 이벤트 전달이 운영체제와 Docker Desktop 구현에 영향을 받는다.

파일 변경 감지가 불안정할 때는 폴링 방식이 도움이 되는 경우가 있다. 폴링은 파일 시스템 이벤트를 기다리는 대신, 일정 간격으로 파일이 바뀌었는지 직접 확인하는 방식이다. 안정성은 좋아질 수 있지만 CPU 사용량이 늘어날 수 있다.

Next.js와 Turbopack 조합에서 모든 문제를 하나의 환경 변수로 해결할 수 있다고 단정하기는 어렵다. 다만 Docker 환경에서 파일 변경 감지 문제가 의심되면 다음 순서로 확인하는 편이 안전하다.

  • 같은 프로젝트를 Docker 밖에서 실행해 본다.
  • next devnext dev --turbo를 각각 실행해 차이를 본다.
  • bind mount 경로가 프로젝트 전체를 덮어쓰는지 확인한다.
  • node_modules가 호스트와 컨테이너 사이에서 섞이지 않는지 확인한다.
  • 새 파일 생성과 기존 파일 수정이 모두 감지되는지 나눠서 확인한다.
파일 변경 감시 도구 화면
파일 변경 감시 도구 화면

개발 서버는 파일 변경을 감지해 브라우저에 결과를 다시 전달한다.

이 과정을 거치면 문제가 Turbopack 자체인지, Docker 파일 시스템 경계인지, 프로젝트 설정인지 좁혀 볼 수 있다.

Docker Compose 예시

아래 예시는 Turbopack 개발 서버를 Docker Compose로 실행하는 단순한 형태다. 실제 프로젝트에서는 Node 버전, 패키지 매니저, 포트, 환경 변수에 맞게 조정해야 한다.

services:
  web:
    image: node:20-alpine
    working_dir: /app
    command: sh -c "npm install && npm run dev:turbo"
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - HOSTNAME=0.0.0.0

Next.js 개발 서버를 컨테이너 밖에서 접속하려면 서버가 컨테이너 내부의 localhost에만 묶이지 않도록 해야 한다. Next.js CLI는 hostname 옵션을 제공한다.

스크립트에서 명시적으로 적는 방식도 가능하다.

{
  "scripts": {
    "dev:turbo": "next dev --turbo -H 0.0.0.0"
  }
}

컨테이너에서 3000 포트를 열고, 호스트에서 localhost:3000으로 접속하는 구조다.

Turbopack에서 문제가 생겼을 때의 판단 순서

Turbopack을 켰을 때 문제가 생기면 바로 복잡한 설정을 바꾸기보다 단순한 순서로 확인하는 것이 좋다.

첫 번째는 Turbopack을 끄고 같은 문제가 생기는지 확인하는 것이다.

npm run dev
npm run dev:turbo

두 실행 결과가 다르면 Turbopack 관련 차이를 의심할 수 있다. 두 실행 결과가 같으면 Docker, 의존성, Next.js 설정, 코드 자체 문제일 가능성이 더 크다.

두 번째는 Docker 밖에서 실행하는 것이다.

npm install
npm run dev:turbo

Docker 밖에서는 정상이고 Docker 안에서만 문제가 생긴다면 bind mount나 컨테이너 환경의 가능성이 높다.

세 번째는 새 파일 생성과 기존 파일 수정 문제를 나눠 보는 것이다. 기존 파일 수정은 반영되는데 새 파일 생성만 인식이 느리다면 파일 감시 범위나 이벤트 전달 문제일 수 있다.

알려진 주의점: Webpack 설정을 그대로 기대하면 안 된다

Turbopack은 Webpack을 더 빠르게 만든 단순한 교체품이라기보다 다른 구조의 번들러에 가깝다. 그래서 Webpack에서 쓰던 설정이 그대로 동작한다고 기대하면 안 된다.

예를 들어 Webpack 전용 플러그인이나 로더를 직접 설정한 프로젝트는 Turbopack에서 같은 방식으로 처리되지 않을 수 있다. Next.js 문서도 Turbopack의 지원 기능과 차이를 구분해서 안내한다.

초보자에게 중요한 판단 기준은 간단하다. next.config.js 또는 next.config.mjs에서 Webpack 설정을 직접 수정하고 있다면 Turbopack 전환 전에 더 조심해야 한다.

const nextConfig = {
  webpack: (config) => {
    // Webpack 전용 설정
    return config
  }
}

module.exports = nextConfig

이런 코드가 있다면 Turbopack에서도 같은 의미로 동작한다고 가정하지 않는 편이 안전하다.

성능 문제와 버그를 구분하는 방법

Turbopack을 켰는데 느리거나 이상하게 동작한다고 해서 모두 Turbopack 버그는 아니다. 성능 문제와 버그를 구분해야 원인을 찾기 쉽다.

성능 문제는 보통 다음처럼 나타난다.

  • 개발 서버 시작이 느리다.
  • 저장 후 반영까지 시간이 길다.
  • CPU 사용량이 높다.
  • Docker 안에서만 느리다.

버그에 가까운 문제는 다음처럼 나타난다.

  • 특정 파일을 수정하면 항상 에러가 난다.
  • Webpack에서는 되는데 Turbopack에서만 모듈을 찾지 못한다.
  • 특정 패키지를 import하면 Turbopack에서만 실패한다.
  • CSS나 이미지 처리 결과가 다르다.

이 둘을 나누면 대응도 달라진다. 성능 문제는 Docker 볼륨, 파일 감시, 프로젝트 크기, 캐시를 본다. 버그에 가까운 문제는 Turbopack 지원 기능, Next.js 버전, 재현 가능한 최소 예제를 확인한다.

초보자에게 추천하는 사용 방식

Turbopack을 처음 쓴다면 처음부터 모든 개발 환경에 강제로 적용하기보다 비교 가능한 형태로 두는 것이 좋다.

package.json은 다음처럼 분리한다.

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

로컬에서는 dev:turbo를 사용해 보고, 문제가 생기면 dev로 비교한다. Docker에서는 먼저 일반 dev가 안정적으로 도는지 확인한 뒤 dev:turbo를 붙인다.

이 순서가 중요한 이유는 한 번에 너무 많은 변수를 바꾸면 원인을 알기 어렵기 때문이다. Next.js 버전, Docker, 볼륨, 패키지 매니저, Turbopack을 동시에 바꾸면 문제가 생겼을 때 어느 지점이 원인인지 좁히기 어렵다.

Docker 컨테이너 기반 개발 워크플로우 개념도
Docker 컨테이너 기반 개발 워크플로우 개념도

Docker 기반 개발에서는 코드, 컨테이너, 개발 서버의 경계를 나눠서 확인하는 것이 중요하다.

정리

Turbopack은 Next.js 개발 서버를 빠르게 만들기 위한 Rust 기반 번들러다. 전체를 매번 다시 처리하기보다 변경된 부분을 중심으로 다시 계산하는 구조를 지향한다. 그래서 프로젝트가 커질수록 개발 중 피드백 시간을 줄이는 데 도움이 될 수 있다.

다만 Turbopack은 Webpack 설정을 그대로 대체하는 완전한 복사본이 아니다. Webpack 전용 설정이나 플러그인에 의존하는 프로젝트에서는 차이가 생길 수 있다.

Docker 컨테이너에서 사용할 때는 bind mount와 파일 변경 감시 문제가 함께 얽힌다. 특히 macOS나 Windows에서 Docker Desktop을 사용하는 경우, 호스트 파일 시스템과 Linux 컨테이너 사이의 경계 때문에 변경 감지가 느리거나 불안정하게 느껴질 수 있다.

실무적으로는 devdev:turbo 스크립트를 분리하고, Docker 밖과 Docker 안을 나눠 비교하는 방식이 가장 안전하다. Turbopack은 빠른 도구지만, 문제가 생겼을 때 되돌릴 수 있는 기준점을 함께 두는 것이 중요하다.

Tags
Next.jsTurbopackDockerFrontend