cargo_metadata

Structured, strongly-typed Rust access to the JSON output of `cargo metadata` and `cargo --message-format=json`.

Library
Cargo
v0.23.1
214stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
48/100Fair
Development Activity12
Maintenance20
Community80
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
85/100Excellent
Architecture85
Code Quality88
Innovation86
Learning Curve80

cargo_metadata is a Rust library that turns the raw JSON produced by cargo metadata into strongly-typed, ergonomic structs so you can inspect a workspace’s packages, dependencies, targets, features, and resolve graph without hand-parsing serde_json values. It also models the streaming --message-format=json output emitted during builds, letting cargo-* subcommands react to compiler messages, artifacts, build-script runs, and diagnostics.

It is the de-facto standard building block for the Rust tooling ecosystem: linters, coverage tools, custom subcommands, and CI utilities lean on it to understand the shape of a project and to consume cargo’s machine-readable output. The crate wraps invocation, feature/flag configuration, and deserialization behind a small MetadataCommand builder and a set of well-documented types.

What You Get

  • A MetadataCommand builder that invokes cargo metadata, forwards --manifest-path, feature flags, and extra args, then deserializes the result.
  • Strongly-typed Metadata, Package, Dependency, Target, Resolve, and Node structs covering the full workspace graph.
  • A streaming Message API (parse_stream) modeling compiler messages, artifacts, build-script output, and build-finished events from --message-format=json.
  • Serde-based serialization and deserialization, so subcommands can both consume and re-emit cargo-compatible JSON.
  • Re-exports of camino, cargo_platform, and semver so version and path types line up with the rest of the cargo ecosystem.

Common Use Cases

  • Building a cargo-* subcommand that needs to know the workspace’s packages, targets, and dependency graph.
  • Writing linters, coverage collectors, or CI tools that consume cargo’s --message-format=json build output.
  • Resolving feature sets and dependency kinds (normal, dev, build) programmatically before running an operation.
  • Generating --message-format=json-like output from your own tooling by reusing the shared types.

Under The Hood

Architecture - The crate centers on src/lib.rs (~47KB), which defines the Metadata, Package, Dependency, Target, Resolve, and Node types plus the MetadataCommand builder. MetadataCommand::exec shells out to cargo metadata --format-version 1, captures stdout, and deserializes it via serde_json (with unbounded_depth enabled for deep graphs). Streaming build output is handled separately in src/messages.rs, where Message::parse_stream wraps a BufRead and yields typed CompilerMessage, Artifact, BuildScript, and BuildFinished variants; diagnostics live in src/diagnostic.rs. Errors flow through a single thiserror-derived enum in src/errors.rs.

Tech Stack - Pure Rust (edition 2021, rust-version 1.88). Core dependencies are serde + serde_json for (de)serialization, semver for version types, camino for UTF-8 paths, cargo-platform for target specs, and thiserror for errors. An optional builder feature pulls in derive_builder to generate builder types for the message structs; an unstable feature gates libtest message parsing. No async runtime and no heavy transitive footprint.

Code Quality - The crate enforces #![deny(missing_docs)], so every public item is documented, and the module-level docs carry runnable doctests for the primary flows. Tests are organized under tests/ with test_samples.rs and selftest.rs plus fixture workspaces in tests/all and tests/basic_workspace that exercise real cargo output across dependency kinds, renamed deps, and rust-version fields. Errors are modeled explicitly rather than panicking, and a str_newtype! macro keeps the many string-wrapper types consistent.

API Design - The public surface is small and discoverable: a fluent MetadataCommand builder for the common path, plus plain data structs you can pattern-match. Getting metadata is a one-liner (MetadataCommand::new().exec().unwrap()), and forwarding --manifest-path or features is a couple of chained calls. Re-exporting camino, semver, and cargo_platform avoids version-mismatch friction, and the streaming Message enum reads naturally in a for/match loop. Documentation on docs.rs is thorough and example-driven.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search