How to vendor Rust dependencies with cargo vendor for offline builds
- Steps
- 6
- Hands-on
- 15 min
- Reading
- 5 min
- Checked
- Oct 26
The short version
Run cargo vendor in your project while you are online. It copies every dependency into a vendor/ folder and prints four lines of config; paste them into .cargo/config.toml. From then on Cargo reads crates from that folder instead of crates.io, so cargo build --offline --locked works with the cable unplugged. In our test, one dependency (serde_json) became 11 crates and 5,806 KB on disk, and Cargo resolved the whole tree with an empty cache in under a second.

What you need
- Rust and Cargo installed (we used cargo 1.91.0)
- A project with a Cargo.toml
- Internet access once, to download the crates
- About 5 to 500 MB of disk per project, depending on the dependency tree
Part of the article Offline Rust builds: 17,527 downloads, almost nobody is shutdown-ready. This page answers one question from it in depth.
On this page · 10 sections
Every Rust build quietly assumes crates.io is one HTTPS call away. We counted what the ecosystem bets on that in Offline Rust builds: almost nobody is shutdown-ready: the six offline-build tools got 17,527 downloads in 90 days, while cargo-chef, which assumes the network is always there, got 1,218,032. Vendoring is free, built into Cargo, and takes about fifteen minutes. Own your supply chain while you still have a connection to copy it from.
Before you start
cargo vendor copies what your Cargo.lock says, so the lockfile is the source of truth. A library crate without a committed lockfile will get whatever versions resolve today. Also note the scope: vendoring covers crates. The Rust toolchain itself (rustc, cargo, std) still comes from rustup, so an offline machine needs its toolchain installed or mirrored separately.
Step 01: Commit a current Cargo.lock
While online, build once or run:
cargo generate-lockfile
git add Cargo.lock
If you already build in CI with --locked, you are done with this step.
Step 02: Run cargo vendor
cargo vendor
Our demo project had a single line in [dependencies], serde_json = "1". Cargo vendored 11 crates in 0.48 seconds (they were already in the local cache; a cold run downloads them first): itoa, memchr, proc-macro2, quote, serde, serde_core, serde_derive, serde_json, syn, unicode-ident and zmij.
Our run on Windows, cargo 1.91.0, Oct 26 2026. Trimmed: 7 of the 11 "Vendoring" lines and the local cache paths are cut for width.
Two details people miss. First, the folder holds more crates than your build uses: cargo tree showed 5 crates in the active tree, but vendor also copied serde_derive, syn, quote, proc-macro2 and unicode-ident, because the lockfile covers every feature and platform. Second, size is dominated by a few big crates. syn alone was 2,318 KB of our 5,806 KB. If the folder gets heavy, cargo-vendor-filterer drops crates for platforms you never build.
Useful flags from the cargo vendor docs: --versioned-dirs puts the version in every folder name (cleaner diffs when re-vendoring), -s path/to/Cargo.toml vendors extra workspaces into the same folder, and --locked fails instead of changing your lockfile.
Step 03: Point Cargo at vendor/
cargo vendor prints exactly what to add. Put it in .cargo/config.toml at the project root:
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
This is Cargo's source replacement: every request for a crates.io crate is answered from the directory instead. The Cargo book is strict about one rule here: the replacement must hold exactly the same code as the original, which is why you should never hand-edit files under vendor/. Each crate carries a .cargo-checksum.json, and Cargo treats vendored sources as read-only. To change a dependency, use [patch] or a path dependency.
Step 04: Prove it with no network and an empty cache
--offline alone can fool you, because Cargo may still find crates in your global cache (~/.cargo/registry). Point CARGO_HOME at an empty folder so the only possible source is vendor/:
CARGO_HOME=/tmp/empty-cargo-home cargo build --offline --locked
On Windows PowerShell: $env:CARGO_HOME="C:\temp\empty"; cargo build --offline --locked.
We ran the cheaper check, cargo tree --offline --locked, with an empty CARGO_HOME, and the full tree resolved from vendor/. Then we tried to add a crate we had not vendored, cargo add --offline anyhow@1, and got the failure you want to see: error: the crate anyhow@1 could not be found in registry index. Nothing leaked in from the network.
Step 05: Ship vendor/ with the source
Two common options:
- Commit it. Simplest for air-gapped or regulated builds. Our 11-crate demo was under 6 MB; real services often run to hundreds of MB, so consider Git LFS or a separate branch.
- Archive it.
tar czf src-with-vendor.tgz Cargo.toml Cargo.lock .cargo src vendorgives the offline machine one file to unpack.
Step 06: Re-vendor when dependencies change
cargo vendor deletes and rewrites vendor/ by default (pass --no-delete to keep old contents). After cargo update or a new dependency, run it again online, review the diff, commit. Put cargo build --offline --locked in CI so a dependency added without re-vendoring fails the build the day it lands, not the day the network goes.
What goes wrong
- "could not be found in registry index" offline: the crate is not in
vendor/. You added a dependency after vendoring. Re-runcargo vendoronline. - A checksum error naming a vendored file: someone edited a file under
vendor/. Revert it and use[patch]instead. - Build passes on your laptop but fails on the offline box: your global cache was filling the gaps. Repeat Step 4 with an empty
CARGO_HOME. - Git dependencies: these are vendored too, and the printed config then includes an extra
[source."git+https://..."]block. Copy all of it, not just the crates-io part. - No toolchain: vendoring does not cover rustc itself. Install the toolchain on the offline machine first, or mirror it (the parent article covers panamax, which mirrors both and has not shipped a release since June 2024).
The ecosystem's bet, in downloads. crates.io API, pulled Oct 26 2026.
When to use something bigger
cargo vendor is per project. If you run many projects offline, cargo-local-registry builds a reusable local registry from lockfiles (10,235 downloads in 90 days, the most popular offline tool we found), and a full crates.io mirror covers everything at the cost of a lot of disk. Start with vendoring: it needs nothing but Cargo.
Related: Offline Rust builds: almost nobody is shutdown-ready, GitHub outages and Rust crates, How to publish a Rust crate, Why crates.io download counts are inflated, and our free Cargo.toml checker.
Sources
All checked October 26, 2026.
- The Cargo Book, cargo vendor: what the command copies, read-only vendored sources, --versioned-dirs, --no-delete, -s, --locked, --offline.
- The Cargo Book, Source Replacement: replace-with, directory sources, the rule that a replacement must match the original source exactly.
- crates.io: cargo-vendor-filterer, cargo-local-registry, panamax, cargo-chef; 90-day download counts from the crates.io API, pulled October 26, 2026.
- Our own test: cargo 1.91.0 on Windows 11, a new project with serde_json = "1", cargo vendor, then cargo tree --offline --locked and cargo add --offline with an empty CARGO_HOME, October 26, 2026.
- Tensorust, Offline Rust builds: almost nobody is shutdown-ready, October 26, 2026.
Do this next
Every number on this page links to its source and was checked on Oct 26, 2026. Spot an error or a newer figure? Email matt@tensorust.com and it gets fixed. Related: Cargo.toml checker, Check your crates.
Read next
- Article · Oct 26, 2026Offline Rust builds: 17,527 downloads, almost nobody is shutdown-ready
- Article · Oct 24, 202634 critical GitHub outages since April. 98% of Rust still lives there
- Article · Oct 17, 2026crates.io download count: 80% of ours arrived with a new version
- Guide · Oct 25, 2026UUID as a primary key in Postgres: use uuidv7(), store it as uuid, and measure
- Guide · Oct 25, 2026Cold email deliverability: set up SPF, DKIM and DMARC, then send slower than you think
Get the next one by email.
What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.
No spam, never sold. Every email has a one-click unsubscribe.