惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
K
Kaspersky official blog
V
Vulnerabilities – Threatpost
Hacker News - Newest:
Hacker News - Newest: "LLM"
Security Archives - TechRepublic
Security Archives - TechRepublic
S
Secure Thoughts
I
Intezer
TaoSecurity Blog
TaoSecurity Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Spread Privacy
Spread Privacy
A
About on SuperTechFans
NISL@THU
NISL@THU
The GitHub Blog
The GitHub Blog
Hugging Face - Blog
Hugging Face - Blog
S
Security @ Cisco Blogs
S
SegmentFault 最新的问题
G
Google Developers Blog
B
Blog
N
News and Events Feed by Topic
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
V2EX - 技术
V2EX - 技术
V
Visual Studio Blog
MyScale Blog
MyScale Blog
Webroot Blog
Webroot Blog
Vercel News
Vercel News
IT之家
IT之家
Microsoft Security Blog
Microsoft Security Blog
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
S
Security Affairs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
博客园 - 叶小钗
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Know Your Adversary
Know Your Adversary
T
Tailwind CSS Blog
F
Fortinet All Blogs
D
DataBreaches.Net
博客园 - Franky
博客园_首页
H
Heimdal Security Blog
宝玉的分享
宝玉的分享
阮一峰的网络日志
阮一峰的网络日志
Attack and Defense Labs
Attack and Defense Labs
Project Zero
Project Zero
雷峰网
雷峰网

Next.js Blog

Next.js Security Release and Our Next Patch Release Turbopack: What's New in Next.js 16.3 Next.js 16.3: AI Improvements Next.js 16.3: Instant Navigations Next.js Across Platforms: Adapters, OpenNext, and Our Commitments Next.js 16.2: AI Improvements Next.js 16.2 Turbopack: What's New in Next.js 16.2 Building Next.js for an agentic future Next.js 16.1 Next.js Security Update: December 11, 2025 Security Advisory: CVE-2025-66478 Next.js 16 Next.js 16 (beta) Next.js 15.5 Next.js 15.4 Next.js 15.3 Building APIs with Next.js Next.js 15.2 Composable Caching with Next.js Next.js 15.1 Our Journey with Caching Next.js 15 Turbopack Dev is Now Stable Next.js 15 RC 2 Next.js 15 RC Next.js 14.2 Next.js 14.1 Next.js 14 How to Think About Security in Next.js Next.js 13.5 Next.js App Router Update Next.js 13.4 Next.js 13.3 Next.js 13.2 Next.js 13.1 Next.js 13 Next.js 12.3 Next.js 12.2 Layouts RFC Next.js 12.1 Next.js 12 Next.js 11.1 Next.js 11 Next.js 10.2 Next.js 10.1 Incrementally Adopting Next.js Next.js 10 Next.js 9.5 Next.js 9.4 Next.js 9.3 Next.js 9.2 Next.js 9.1.7 Introducing Create Next App Next.js 9.1 Next.js 9.0.7 Next.js 9 Next.js 8.1 Next.js 8.0.4 Styling Next.js with Styled JSX Next.js 8 Webpack Memory Improvements Next.js 8 Next.js 7 Next.js 6.1 Next.js 6 and Nextjs.org Next.js 5.1: Faster Page Resolution, Environment Config & More Next.js 5: Universal Webpack, CSS Imports, Plugins and Zones
Inside Turbopack: Building Faster by Building Less
Anthony Shew, Benjamin Woodruff, Tobias Koppers · 2026-01-21 · via Next.js Blog

Edit. Save. Refresh. Wait… Wait… Wait…

Compiling code usually means waiting, but Turbopack makes iteration loops fast with caching and incremental computation. Not every modern bundler uses an incremental approach, and that’s with good reason. Incremental computation can introduce significant complexity and opportunities for bugs. Caches require extra tracking and copies of data, adding both CPU and memory overhead. When applied poorly, caching can actually make performance worse.

Despite all of this, we took on these challenges because we knew that an incremental architecture would be critical to Turbopack’s success. Turbopack is the new default bundler for Next.js, a framework that is used to build some of the largest web applications in the world. We needed to enable instant builds and a fast as-you-type interactive React Fast Refresh experience, even for the largest and most challenging workloads. Our incremental architecture is core to achieving this.

Turbopack’s architecture was built ground-up with caching in mind. Its incremental design is based on over a decade of research. We built on first-hand experience from challenges in implementing caching in webpack and drew inspiration from Salsa (which powers Rust-Analyzer and Ruff), Parcel, the Rust compiler’s query system, Adapton, and many others.

Turbopack achieves a fine-grained cache by automatically tracking how internal functions are called and what values they depend on. When something changes we know how to recompute the results with minimal work.

Background: Manual incremental computation

Many build systems include explicit dependency graphs that must be manually populated when evaluating build rules. Explicitly declaring your dependency graph can theoretically give optimal results, but in practice it leaves room for errors.

The difficulty of specifying an explicit dependency graph means that usually caching is done at a coarse file-level granularity. This granularity does have some benefits: fewer incremental results means less data to cache, which might be worth it if you have limited disk space or memory.

An example of such an architecture is GNU Make, where output targets and prerequisites are manually configured and represented as files. Systems like GNU Make miss caching opportunities due to their coarse granularity: they do not understand and cannot cache internal data structures within the compiler.

Function-level fine-grained automatic incremental computation

In Turbopack, the relationship between input files and resulting build artifacts isn’t straightforward. Bundlers employ whole-program analysis for dead code elimination ("tree shaking") and clustering of common dependencies in the module graph. Consequently, the build artifacts (JavaScript files shared across multiple application routes) form complex many-to-many relationships with input files.

Turbopack uses a very fine-grained caching architecture. Because manually declaring and adding dependencies to a graph is prone to human errors, Turbopack needs an automated solution that can scale.

Tracking the compilation graph with value cells

To facilitate automatic caching and dependency tracking, Turbopack introduces a concept of “value cells” (Vc<…>). Each value cell represents a fine-grained piece of execution, like a cell in a spreadsheet. When reading a cell, it records the currently executing function and all of its cells as dependent on that cell. This is similar to how signals work in frameworks like SolidJS.

By not marking cells as dependencies until they are read, Turbopack achieves finer-grained caching than a traditional top-down memoization approach would provide. For example, an argument might be an object or mapping of many value cells. Instead of needing to recompute our tracked function when any part of the object or mapping changes, it only needs to recompute the tracked function when a cell that it has actually read changes.

Value cells represent nearly everything inside of Turbopack, such as a file on disk, an abstract syntax tree (AST), metadata about imports and exports of modules, or clustering information used for chunking and bundling.

Marking dirty and propagating changes

When Turbopack executes functions for the first time, it builds a graph of functions and the value cells they create or depend on. The graph’s roots are the requested outputs (bundled assets), and the leaves are source code files. There are intermediate representations in the middle, such as ASTs, metadata, partially-transformed modules, or chunking information.

When our file system watcher finds source code that has changed, it marks all functions that read the file’s value cell as “dirty” and queues them for re-computation.

The dirtied function reading the file might parse or transform the JavaScript module and produce a new intermediate representation. Recomputing the function update cells containing changed intermediate representations, which may mark more functions as dirty. Cell updates are skipped if the cell contents are equal. This propagation bubbles up the graph until all affected functions have been recomputed.

As an additional optimization, execution is "demand-driven," meaning the system defers re-execution of dirty functions until they become part of an "active query". In development, an active query could be a currently open webpage with hot reloading enabled. In builds, this is a request for the full production app.

Aggregation graphs

While most operations, like the dirty propagation algorithm, only require information about adjacent edges and neighboring nodes in the graph, some operations need to query information about more significant portions of the dependency graph:

  • Finding all dirty nodes when a sub-graph becomes part of a new active query, so we can schedule re-computation.
  • Collecting errors, warnings, or lints of a sub-graph.
  • Waiting for computation of a sub-graph to finish.

Because we maintain a fine-grained cache, the graph can contain hundreds of thousands or even millions of intermediate results. Visiting significant portions of this graph would be expensive.

To make these queries efficient, Turbopack uses an additional data structure on top of the dependency graph, called the “aggregation graph”.

When we build or update the dependency graph, we maintain parallel nodes in the aggregation graph that summarize part of the dependency graph. Some frequently accessed information, like emitted errors or warnings, is attached to the aggregation nodes.

This aggregation graph has multiple layers of resolution, with higher aggregation layers referencing more functions in each node, decreasing the resolution, and reducing the number of nodes that must be traversed when collecting information.

Every potential active query (e.g. an application entrypoint or route) represents a root in the aggregation graph. At the final aggregation graph layer, each root represents the information for itself and all of the children in the original dependency graph. Adding roots to the dependency graph can require a reorganization of the aggregation graph, but that’s an infrequent operation.

File system caching

Until our recent Next.js 16.1 release, all of these caches were stored only in memory.

In this new release, we shipped file system caching for next dev as stable and on-by-default. This cache allows us to persist the dependency graph, the aggregation graph, and all of the intermediate results stored in value cells to disk. When next dev is restarted, it can quickly resume from this warm cache.

File system caching came with its own set of challenges, and it took us over a year of dedicated work to meet our own high performance and quality bar. We'll dive into that soon in an upcoming engineering blog post.

Feedback and Community

Share your feedback and help shape the future of Next.js: