Cargo's Build Directory Layout v2: A Guide for Testing and Migration

<h2 id="introduction">Introduction</h2> <p>The Rust community is preparing for a significant change in how Cargo organizes intermediate build artifacts. With the nightly-only <code>-Zbuild-dir-new-layout</code> flag, developers can now test the proposed new layout before it becomes the default. While the build directory structure is officially internal, many projects have come to depend on its details due to missing features in Cargo. We need your help to identify tools, scripts, and workflows that rely on the current layout so they can be updated. A crater run has already been performed, but it cannot cover every scenario. This article explains how to test the new layout, what to watch out for, and what is changing—and what is staying the same.</p><figure style="margin:20px 0"><img src="https://www.rust-lang.org/static/images/rust-social-wide.jpg" alt="Cargo&#039;s Build Directory Layout v2: A Guide for Testing and Migration" style="width:100%;height:auto;border-radius:8px" loading="lazy"><figcaption style="font-size:12px;color:#666;margin-top:5px">Source: blog.rust-lang.org</figcaption></figure> <h2 id="how-to-test">How to Test the New Layout</h2> <p>Testing requires at least the nightly release from <strong>2026-03-10</strong>. Run your test suites, release processes, and any other operations that interact with the build directory (<code>target-dir</code> or <code>build-dir</code>) using the <code>-Zbuild-dir-new-layout</code> flag. For example:</p> <pre><code>$ cargo test -Zbuild-dir-new-layout</code></pre> <p>Note that failures may not be exclusive to the new layout. Since Cargo 1.91, you can separate intermediate build artifacts (using the <code>CARGO_BUILD_BUILD_DIR</code> environment variable set to <code>build</code>) from final artifacts (still in <code>target-dir</code>). This separation is part of the ongoing changes. We are evaluating whether to make the new layout the default in <a href="https://github.com/rust-lang/cargo/issues/16147">issue #16147</a>.</p> <p>When you encounter issues, you can help by:</p> <ul> <li><strong>Fixing local problems</strong> – adjust your own scripts or configurations.</li> <li><strong>Reporting upstream issues</strong> – file bug reports with affected tools and link to the tracking issue.</li> <li><strong>Providing feedback</strong> – comment on the tracking issue with your findings.</li> </ul> <h2 id="known-failure-modes">Known Failure Modes</h2> <p>Several common patterns are known to break with the new layout. Here are the main categories and how to address them.</p> <h3 id="inferring-bin-path-from-test-path">Inferring a Binary’s Path from a Test’s Path</h3> <p>Some code attempts to deduce the path of a <code>[[bin]]</code> artifact from the path of a <code>[[test]]</code> artifact. This will no longer work because the new layout reorganizes paths. Instead:</p> <ul> <li>Use <code>std::env::var_os("CARGO_BIN_EXE_*")</code> (available since Cargo 1.94) and keep the inference as a fallback for older Cargo versions.</li> <li>Alternatively, use the <code>env!("CARGO_BIN_EXE_*")</code> macro at compile time.</li> </ul> <h3 id="build-scripts-looking-up-target-dir">Build Scripts Looking Up target-dir</h3> <p>Build scripts that rely on <code>OUT_DIR</code> or their own binary path to infer the <code>target-dir</code> may break. See <a href="https://github.com/rust-lang/cargo/issues/13663">issue #13663</a>. Current workarounds need to be updated to support the new layout.</p> <h3 id="looking-up-user-requested-artifacts">Looking Up User‑Requested Artifacts from rustc</h3> <p>Some tools query rustc for the location of requested artifacts. This pattern is affected by the layout change. See <a href="https://github.com/rust-lang/cargo/issues/13672">issue #13672</a>. Again, workarounds must be revised.</p> <h2 id="library-support-status">Library Support Status</h2> <p>Several popular testing and tooling libraries have already been updated or have open issues. As of publication:</p> <ul> <li><strong>assert_cmd</strong> – fixed</li> <li><strong>cli_test_dir</strong> – <a href="https://github.com/rust-cli/cli_test_dir/issues/65">issue #65</a></li> <li><strong>compiletest_rs</strong> – <a href="https://github.com/rust-lang/compiletest-rs/issues/309">issue #309</a></li> <li><strong>executable-path</strong> – fixed</li> <li><strong>snapbox</strong> – fixed</li> <li><strong>term-transcript</strong> – <a href="https://github.com/rust-cli/term-transcript/issues/269">issue #269</a></li> <li><strong>test_bin</strong> – <a href="https://github.com/rust-cli/test_bin/issues/13">issue #13</a></li> <li><strong>trycmd</strong> – fixed</li> </ul> <h2 id="whats-changing-vs-not">What’s Changing vs. Not Changing</h2> <h3 id="not-changing">What Is Not Changing</h3> <p>The layout of <strong>final artifacts</strong> within the <code>target</code> directory remains the same. The nesting of build artifacts under the profile and the target tuple (if specified) is also preserved.</p> <h3 id="changing">What Is Changing</h3> <p>The new layout switches from organizing artifacts by content type to scoping them by the <strong>package name</strong> and a <strong>hash of the build unit and its inputs</strong>. Here is an illustrative comparison (assuming a workspace with packages <code>lib</code> and <code>bin</code>, both with build scripts):</p> <p><strong>Current layout (simplified):</strong></p> <pre><code>build-dir/ ├── CACHEDIR.TAG └── debug/ ├── .cargo-lock ├── .fingerprint/ │ ├── bin-[BUILD_SCRIPT_RUN_HASH]/* │ ├── bin-[BUILD_SCRIPT_BIN_HASH]/* │ ├── bin-[HASH]/* │ ├── lib-[BUILD_SCRIPT_RUN_HASH]/* │ ├── lib-[BUILD_SCRIPT_BIN_HASH]/* │ └── lib-[HASH]/* ├── build/ │ ├── bin-[BIN_HASH]/* │ ├── bin-[RUN_HA... ...</code></pre> <p>The new layout will change this structure to be more predictable and isolated per package. For complete details, refer to the official RFC or tracking issue.</p> <h2 id="conclusion">Conclusion</h2> <p>We strongly encourage all developers who use Cargo’s build directory—directly or through tooling—to test the new layout with the nightly toolchain and report any issues. Your feedback is crucial for a smooth transition. For questions or to share results, please comment on <a href="https://github.com/rust-lang/cargo/issues/16147">tracking issue #16147</a>.</p>
Tags: