Cargo and Package Management

Publishing to crates.io

Publishing to crates.io packages your crate's source files into a compressed .crate tarball and uploads it to the public Rust package registry so anyone can depend on it via cargo add <crate> or install its binaries via cargo install <crate>.

Publishing Workflow:
  1. Verify metadata & include/exclude rules (`cargo package --list`)
  2. Dry-run full verification build        (`cargo publish --dry-run`)
  3. Authenticate (`cargo login` or CI Trusted Publishing / `CARGO_REGISTRY_TOKEN`)
  4. Upload permanent release               (`cargo publish`)

Required Cargo.toml Metadata for crates.io

Before crates.io accepts a package, the [package] section of Cargo.toml must include a clear description and license, and all dependencies must come from a registry (pure path or git dependencies without a version are rejected):

[package]
name = "fast_varint"
version = "0.1.0"
edition = "2024"
rust-version = "1.85"
description = "Zero-allocation LEB128 variable-length integer encoding and decoding"
license = "MIT OR Apache-2.0"
repository = "https://github.com/example/fast_varint"
homepage = "https://github.com/example/fast_varint"
documentation = "https://docs.rs/fast_varint"
readme = "README.md"
keywords = ["varint", "leb128", "encoding", "no-std"]
categories = ["encoding", "no-std"]
# Exclude large test fixtures or CI configs to keep the .crate download small (<10 MiB limit)
exclude = [
    "fuzz/",
    "testdata/*.bin",
    ".github/",
]

Note that crates.io enforces a maximum of 5 keywords and 5 categories (chosen from the official crates.io category slugs).

Inspecting and Dry-Running Before Publishing

Published versions on crates.io are permanent and immutable—once 0.1.0 is uploaded, its contents can never be overwritten or deleted. Always inspect the packaged file list and perform a dry run before publishing:

# 1. Inspect every file that will be bundled into the .crate archive
cargo package --list

# 2. Unpack the .crate archive into target/package/ and compile it from scratch
#    to verify no untracked local files were accidentally required
cargo publish --dry-run

# 3. Publish for real once the dry run succeeds
cargo publish

Handling Defective Releases with cargo yank

Although a published version cannot be deleted or overwritten (so existing Cargo.lock files across the world never break), you can yank a broken or vulnerable version:

# Prevent new projects from resolving version 0.1.0 during `cargo add` or `cargo update`
cargo yank --version 0.1.0

# Undo a yank if it was done by mistake
cargo yank --version 0.1.0 --undo
Action Existing Projects with 0.1.0 in Cargo.lock New Projects Running cargo add / cargo update
Normal Version (0.1.0) Downloads and builds 0.1.0 normally Can select 0.1.0
Yanked Version (cargo yank --version 0.1.0) Continues to download and build 0.1.0 (Cargo.lock is never broken!) Never selects 0.1.0 (resolver skips yanked versions)
pub fn encode_u64_leb128(mut value: u64, out: &mut [u8; 10]) -> &[u8] {
    let mut i = 0;
    loop {
        let mut byte = (value & 0x7F) as u8;
        value >>= 7;
        if value != 0 {
            byte |= 0x80;
        }
        out[i] = byte;
        i += 1;
        if value == 0 {
            break;
        }
    }
    &out[..i]
}

fn main() {
    let mut buf = [0u8; 10];
    let encoded = encode_u64_leb128(300, &mut buf);
    println!("300 encoded as LEB128: {encoded:02x?}");
}
300 encoded as LEB128: [ac, 02]