Turbopack Performance Benchmarks
Summary
- We are thankful for the work of the entire OSS ecosystem and the incredible interest and reception from the Turbopack release. We look forward to continuing our collaboration with and integration into the broader Web ecosystem of tooling and frameworks.
- In this article, you’ll find our methodology and documentation supporting the benchmarks that show Turbopack is up to 10x and 700x faster than existing approaches.
- Turbopack and Next.js 13.0.1 are out addressing a regression that snuck in prior to public release and after the initial benchmarks were taken. We also fixed an incorrect rounding bug on our website (
0.01s
→15ms
). We appreciate Evan You's work that helped us identify and correct this. - We’re excited to continue to evolve the incremental build architecture of Turbopack. We believe that there are still significant performance wins on the table.
At Next.js Conf, we announced our latest open-source project: Turbopack, an incremental bundler and build system optimized for JavaScript and TypeScript, written in Rust.
The project began as an exploration to improve Webpack’s performance and create ways for it to more easily integrate with tooling moving forward. In doing so, the team realized that a greater effort was necessary. While we saw opportunities for better performance, the premise of a new architecture that could scale to the largest projects in the world was inspiring.
In this post, we’ll explore why Turbopack is so fast, how its incremental engine works, and benchmark it against existing approaches.
Why is Turbopack blazing fast?
Turbopack’s speed comes from its incremental computation engine. Similar to trends we've seen in frontend state libraries, computational work is split into reactive functions that enable Turbopack to apply updates to an existing compilation without going through a full graph recomputation and bundling lifecycle.
This does not work like traditional caching where you look up a result from a cache before an operation and then decide whether or not to use it. That would be too slow.
Instead, Turbopack skips work altogether for cached results and only recomputes affected parts of its internal dependency graph of functions. This makes updates independent of the size of the whole compilation, and eliminates the usual overhead of traditional caching.
Benchmarking Turbopack, Webpack, and Vite
We created a test generator that makes an application with a variable amount of modules to benchmark cold startup and file updating tasks. This generated app includes entries for these tools:
- Next.js 11
- Next.js 12
- Next.js 13 with Turbopack
- Vite
As the current state of the art, we're including Vite along with Webpack-based Next.js solutions. All of these toolchains point to the same generated component tree, assembling a Sierpiński triangle in the browser, where every triangle is a separate module.
Cold startup time
This test measures how fast a local development server starts up on an application of various sizes. We measure this as the time from startup (without cache) until the app is rendered in the browser. We do not wait for the app to be interactive or hydrated in the browser for this dataset.
Next.js 13
turbo
1.1s
Next.js 12
3.4s
Vite
4.8s
Next.js 11
7.7s
Data
To run this benchmark yourself, clone vercel/turbo
and then use this command from the root:
TURBOPACK_BENCH_COUNTS=1000,5000,10000,30000 TURBOPACK_BENCH_BUNDLERS=all cargo bench -p next-dev "startup/(Turbopack SSR|Next.js 12 SSR|Next.js 11 SSR|Vite CSR)."
Here are the numbers we were able to produce on a 14” MacBook Pro 2021, M1 Max, 64GB RAM, macOS 12.6 (21G115):
bench_startup/Next.js 11 SSR/1000 modules 7.7±0.06s
bench_startup/Next.js 11 SSR/5000 modules 24.8±0.11s
bench_startup/Next.js 11 SSR/10000 modules 49.4±0.28s
bench_startup/Next.js 11 SSR/30000 modules 176.2±1.42s
bench_startup/Next.js 12 SSR/1000 modules 3.4±0.01s
bench_startup/Next.js 12 SSR/5000 modules 10.7±0.02s
bench_startup/Next.js 12 SSR/10000 modules 20.1±0.07s
bench_startup/Next.js 12 SSR/30000 modules 76.6±0.66s
bench_startup/Turbopack SSR/1000 modules 1125.3±44.54ms
bench_startup/Turbopack SSR/5000 modules 3.6±0.02s
bench_startup/Turbopack SSR/10000 modules 7.5±0.44s
bench_startup/Turbopack SSR/30000 modules 22.3±1.29s
bench_startup/Vite CSR/1000 modules 4.8±0.02s
bench_startup/Vite CSR/5000 modules 19.2±0.15s
bench_startup/Vite CSR/10000 modules 37.2±0.29s
bench_startup/Vite CSR/30000 modules 109.5±1.14s
File updates (HMR)
We also measure how quickly the development server works from when an update is applied to a source file to when we receive a custom browser event that the modified code was executed.
Note that executing modified code does not mean that the changes are visible to the user yet. When a React component changes, it still needs to be re-rendered by the browser. With this methodology, we are focusing only on the time the compiler takes to do its work and the time it takes for the browser to evaluate an updated module.
For Hot Module Reloading (HMR) benchmarks, we first start the dev server on a fresh installation with the test application. We then run five changes to warm up the tooling. This step is important as it prevents discrepancies that can arise with cold processes.
Once our tooling is warmed up, we measure the sixth file update. After repeating this 10 times, we use the average as our final number.
Next.js 13
turbo
15ms
Vite
87ms
Next.js 12
134ms
Next.js 11
273ms
From our benchmarks, we find the following:
- Turbopack HMR is 10x faster than Vite once the application scales above 30k modules. These marks continue to improve with more modules, showing 20x faster above 50k modules.
- Turbopack HMR is 700x faster than Webpack-based Next.js 11 for large applications with over 50k modules.
The takeaway: Turbopack performance is a function of the size of an update, not the size of an application.
For more info, visit the comparison docs for Vite and Webpack.
Data
To run this benchmark yourself, clone vercel/turbo
and then use this command from the root:
TURBOPACK_BENCH_COUNTS=10,100,200,500,1000,2000,3000,4000,5000,10000,20000,30000,50000 TURBOPACK_BENCH_BUNDLERS=all cargo bench -p next-dev "hmr_to_eval/(Turbopack SSR|Next.js 12 SSR|Next.js 11 SSR|Vite CSR)"
Here are the numbers we were able to produce on a 14” MacBook Pro 2021, M1 Max, 64GB RAM, macOS 12.6 (21G115):
bench_hmr_to_eval/Next.js 11 SSR/10 modules 77.9±21.03ms
bench_hmr_to_eval/Next.js 11 SSR/100 modules 100.5±2.04ms
bench_hmr_to_eval/Next.js 11 SSR/200 modules 98.7±4.48ms
bench_hmr_to_eval/Next.js 11 SSR/500 modules 140.0±14.06ms
bench_hmr_to_eval/Next.js 11 SSR/1000 modules 273.2±17.11ms
bench_hmr_to_eval/Next.js 11 SSR/2000 modules 404.0±24.81ms
bench_hmr_to_eval/Next.js 11 SSR/3000 modules 498.3±22.10ms
bench_hmr_to_eval/Next.js 11 SSR/4000 modules 698.8±54.46ms
bench_hmr_to_eval/Next.js 11 SSR/5000 modules 849.7±14.64ms
bench_hmr_to_eval/Next.js 11 SSR/10000 modules 1713.9±32.96ms
bench_hmr_to_eval/Next.js 11 SSR/20000 modules 5.0±0.12s
bench_hmr_to_eval/Next.js 11 SSR/30000 modules 6.9±1.75s
bench_hmr_to_eval/Next.js 11 SSR/50000 modules 11.6±0.50s
bench_hmr_to_eval/Next.js 12 SSR/10 modules 50.2±5.68ms
bench_hmr_to_eval/Next.js 12 SSR/100 modules 45.7±2.99ms
bench_hmr_to_eval/Next.js 12 SSR/200 modules 50.6±8.27ms
bench_hmr_to_eval/Next.js 12 SSR/500 modules 93.9±19.93ms
bench_hmr_to_eval/Next.js 12 SSR/1000 modules 133.9±12.69ms
bench_hmr_to_eval/Next.js 12 SSR/2000 modules 147.4±24.38ms
bench_hmr_to_eval/Next.js 12 SSR/3000 modules 210.7±33.00ms
bench_hmr_to_eval/Next.js 12 SSR/4000 modules 295.0±21.65ms
bench_hmr_to_eval/Next.js 12 SSR/5000 modules 386.2±84.54ms
bench_hmr_to_eval/Next.js 12 SSR/10000 modules 1067.1±133.67ms
bench_hmr_to_eval/Next.js 12 SSR/20000 modules 2.8±0.09s
bench_hmr_to_eval/Next.js 12 SSR/30000 modules 5.4±0.50s
bench_hmr_to_eval/Next.js 12 SSR/50000 modules 8.5±0.32s
bench_hmr_to_eval/Turbopack SSR/10 modules 13.3±0.49ms
bench_hmr_to_eval/Turbopack SSR/100 modules 13.8±1.10ms
bench_hmr_to_eval/Turbopack SSR/200 modules 14.5±2.18ms
bench_hmr_to_eval/Turbopack SSR/500 modules 14.3±1.63ms
bench_hmr_to_eval/Turbopack SSR/1000 modules 15.3±0.27ms
bench_hmr_to_eval/Turbopack SSR/2000 modules 14.1±0.14ms
bench_hmr_to_eval/Turbopack SSR/3000 modules 15.1±0.37ms
bench_hmr_to_eval/Turbopack SSR/4000 modules 16.0±0.31ms
bench_hmr_to_eval/Turbopack SSR/5000 modules 16.5±0.41ms
bench_hmr_to_eval/Turbopack SSR/10000 modules 14.9±1.35ms
bench_hmr_to_eval/Turbopack SSR/20000 modules 15.3±1.52ms
bench_hmr_to_eval/Turbopack SSR/30000 modules 15.1±1.03ms
bench_hmr_to_eval/Turbopack SSR/50000 modules 16.7±3.73ms
bench_hmr_to_eval/Vite CSR/10 modules 94.8±5.24ms
bench_hmr_to_eval/Vite CSR/100 modules 102.4±2.32ms
bench_hmr_to_eval/Vite CSR/200 modules 101.7±2.39ms
bench_hmr_to_eval/Vite CSR/500 modules 100.1±4.24ms
bench_hmr_to_eval/Vite CSR/1000 modules 86.5±9.13ms
bench_hmr_to_eval/Vite CSR/2000 modules 111.6±3.76ms
bench_hmr_to_eval/Vite CSR/3000 modules 105.0±2.51ms
bench_hmr_to_eval/Vite CSR/4000 modules 99.0±12.26ms
bench_hmr_to_eval/Vite CSR/5000 modules 92.5±22.77ms
bench_hmr_to_eval/Vite CSR/10000 modules 110.4±32.82ms
bench_hmr_to_eval/Vite CSR/20000 modules 204.4±61.72ms
bench_hmr_to_eval/Vite CSR/30000 modules 256.2±67.72ms
bench_hmr_to_eval/Vite CSR/50000 modules 509.8±137.92ms
Visit the Turbopack benchmark documentation to run the benchmarks yourself. If you have questions about the benchmark, please open an issue on GitHub.
The future of the open-source Web
Our team has taken the lessons from 10 years of Webpack, combined with the innovations in incremental computation from Turborepo and Google's Bazel, and created an architecture ready to support the coming decades of computing.
Our goal is to create a system of open source tooling that helps to build the future of the Web—powered by Turbopack. We're creating a reusable piece of architecture that will make both development and warm production builds faster for everyone.
For Turbopack's alpha, we are including it in Next.js 13. But, in time, we hope that Turbopack will power other frameworks and builders as a seamless, low-level, incremental engine to build great developer experiences with.
We look forward to being a part of the community bringing developers better tooling so that they can continue to deliver better experiences to end users. If you’d like to learn more about Turbopack benchmarks, visit turbo.build. To try out Turbopack in Next.js 13, visit nextjs.org.