
Managing Cargo Dependencies
- 2 installs
- 1.6k repo stars
- Updated August 5, 2026
- hashintel/hash
Provides Cargo.toml dependency management patterns for the HASH workspace: adding, updating, version pinning, and default features.
About
Guides adding and organizing dependencies in Cargo.toml within the HASH workspace structure, covering version pinning, default features, and public dependencies. A developer uses it when managing crates in the HASH monorepo.
- Uses workspace.dependencies and section organization
- Covers default-features config and public vs private deps
Managing Cargo Dependencies by the numbers
- 2 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #101 of 121 Rust skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hashintel/hash --skill managing-cargo-dependenciesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | August 5, 2026 |
| Repository | hashintel/hash ↗ |
What it does
Provides Cargo.toml dependency management patterns for the HASH workspace: adding, updating, version pinning, and default features.
Files
Cargo Dependencies Management
Guidance for adding and managing dependencies in Cargo.toml files within the HASH repository's workspace structure.
Core Principles
HASH uses a strict workspace dependency pattern:
✅ DO:
- Add external dependencies to workspace root
[workspace.dependencies] - Use caret version specifiers (e.g.,
version = "1.0.0"=^1.0.0) - Set
default-features = falsefor all dependencies unless specifically needed - Use
workspace = truein package Cargo.toml - Organize dependencies into 4 sections with comment headers
- Use
public = truefor dependencies exposed in public API - Align dependency names using spaces for readability
❌ DON'T:
- Add version numbers directly in package Cargo.toml
- Use exact versions with
=prefix (e.g.,=1.0.0) in workspace root - Enable
default-featureswithout considering impact - Mix different dependency types without section comments
- Forget
public = truefor dependencies exposed in public API
Quick Reference
The 4-Section Pattern
Every package Cargo.toml must organize dependencies into these sections:
[dependencies]
# Public workspace dependencies
hash-graph-types = { workspace = true, public = true }
hashql-core = { workspace = true, public = true }
# Public third-party dependencies
serde = { workspace = true, public = true, features = ["derive"] }
tokio = { workspace = true, public = true }
# Private workspace dependencies
error-stack = { workspace = true }
hash-codec = { workspace = true }
# Private third-party dependencies
tracing = { workspace = true }
regex = { workspace = true }Keep all 4 section comments even if a section is empty.
Quick Add Process
1. Check workspace root - Is dependency already there? 2. Add to workspace if needed - With caret version 1.2.3 3. Determine section - Public workspace/third-party or private? 4. Add to package - Use workspace = true (+ public = true if needed)
Detailed Guides
Choose the guide that matches the task:
workspace-setup.md
Use when: Adding new dependencies to workspace root
- How to add external crates to workspace
- Version pinning with exact versions
- Default features configuration
- Workspace member paths
package-dependencies.md
Use when: Adding dependencies to a package Cargo.toml
- The 4-section organizational structure
- Public vs private dependencies
- When to use
public = true - Alignment and formatting rules
- Feature configuration
examples-reference.md
Use when: Looking for real examples from HASH codebase
- Complete examples from
@local/codec - Complete examples from
@local/hashql/core - Optional dependencies pattern
- dev-dependencies structure
Common Patterns
Adding a New External Dependency
# 1. Add to workspace root Cargo.toml
[workspace.dependencies]
my-crate = { version = "1.2.3", default-features = false }
# 2. Add to package Cargo.toml (appropriate section)
[dependencies]
# Private third-party dependencies
my-crate = { workspace = true }Making a Dependency Public
# Use when the dependency appears in your public API
serde = { workspace = true, public = true, features = ["derive"] }
tokio = { workspace = true, public = true }Optional Dependencies
[dependencies]
serde = { workspace = true, optional = true, features = ["derive"] }
[features]
serde = ["dep:serde", "other-dep/serde"]References
- workspace-setup.md - Workspace root configuration
- package-dependencies.md - Package dependency structure
- examples-reference.md - Real codebase examples
- Workspace Cargo.toml - Root workspace configuration
- hash-codec/Cargo.toml - Reference example
- hashql-core/Cargo.toml - Reference example
Examples Reference
Real examples from the HASH codebase demonstrating dependency patterns.
---
Example 1: @local/codec
Complete example from hash-codec/Cargo.toml
Full Dependencies Section
[dependencies]
# Public workspace dependencies
error-stack = { workspace = true, public = true, optional = true }
harpc-wire-protocol = { workspace = true, public = true, optional = true }
# Public third-party dependencies
bytes = { workspace = true, public = true }
serde_core = { workspace = true, public = true, optional = true }
uuid = { workspace = true, public = true, optional = true, features = ["serde"] }
# Private workspace dependencies
# Private third-party dependencies
dashu-base = { workspace = true, optional = true, features = ["std"] }
derive_more = { workspace = true, optional = true, features = ["display", "error"] }
simple-mermaid = { workspace = true }Key Points
- ✅ All 4 section comments present (even when empty - line "Private workspace dependencies")
- ✅
public = truefor dependencies exposed in public API (bytes,uuid) - ✅ No
public = truefor internal dependencies (simple-mermaid) - ✅ Alignment within each section
- ✅ Many
optional = truedependencies activated via[features]
Features Configuration
[features]
bytes = ["dep:bytes"]
serde = ["dep:serde_core", "dep:uuid", "uuid/serde"]
json = ["serde", "serde_json"]---
Example 2: @local/hashql/core
Complete example from hashql-core/Cargo.toml
Full Dependencies Section
[dependencies]
# Public workspace dependencies
hash-graph-types = { workspace = true, public = true }
hashql-diagnostics = { workspace = true, public = true }
# Public third-party dependencies
anstyle = { workspace = true, public = true }
foldhash = { workspace = true, public = true }
hashbrown = { workspace = true, public = true }
# Private workspace dependencies
# Private third-party dependencies
bitvec = { workspace = true, features = ["alloc"] }
derive_more = { workspace = true, features = ["debug", "from"] }
unicode-segmentation = { workspace = true }Key Points
- ✅ Empty "Private workspace dependencies" section kept
- ✅ Public workspace crates (
hash-graph-types,hashql-diagnostics) - ✅ Public third-party crates (
anstyle,foldhash,hashbrown) - ✅ Features specified at package level (
bitvec,derive_more) - ✅ Perfect alignment
---
Example 3: Typical Backend Service
Pattern for a backend service package:
[dependencies]
# Public workspace dependencies
hash-graph-types = { workspace = true, public = true }
error-stack = { workspace = true, public = true }
# Public third-party dependencies
serde = { workspace = true, public = true, features = ["derive"] }
tokio = { workspace = true, public = true }
# Private workspace dependencies
hash-codec = { workspace = true }
# Private third-party dependencies
tracing = { workspace = true }
regex = { workspace = true }
serde_json = { workspace = true }
tokio-util = { workspace = true, features = ["codec"] }
derive_more = { workspace = true, features = ["debug", "display", "from"] }---
Example 4: dev-dependencies
Dev dependencies don't need 4-section structure:
[dev-dependencies]
insta = { workspace = true }
proptest = { workspace = true }
rstest = { workspace = true }
test-strategy = { workspace = true }
tokio = { workspace = true, features = ["test-util"] }Note: Can add features to dev-dependencies for testing.
---
Example 5: Optional Dependencies Pattern
Full pattern with optional dependencies:
[dependencies]
# Public workspace dependencies
error-stack = { workspace = true, public = true, optional = true }
# Public third-party dependencies
serde = { workspace = true, public = true, optional = true, features = ["derive"] }
# Private workspace dependencies
# Private third-party dependencies
tracing = { workspace = true }
[features]
default = []
serde = ["dep:serde", "error-stack/serde"]
std = ["error-stack/std"]---
Example 6: Feature-Rich Dependency
When a dependency needs many features:
[dependencies]
# Private third-party dependencies
tokio = {
workspace = true,
features = [
"rt-multi-thread",
"macros",
"signal",
"sync",
"time",
"fs",
"io-util",
],
}Note: Multi-line format when feature list is long.
---
Example 7: Workspace Member Reference
Adding a new workspace member:
# In workspace root Cargo.toml
[workspace.dependencies]
my-new-crate.path = "libs/@local/my-new-crate"
# In package Cargo.toml
[dependencies]
# Public workspace dependencies
my-new-crate = { workspace = true, public = true }---
Anti-Patterns to Avoid
❌ Version in Package
# WRONG - version should be in workspace root only
[dependencies]
serde = { version = "1.0.228", features = ["derive"] }❌ Exact Pinning in Workspace
# WRONG - use caret versions, let Cargo.lock handle exact pinning
[workspace.dependencies]
serde = { version = "=1.0.228", default-features = false }❌ Missing Section Comments
# WRONG - missing section structure
[dependencies]
serde = { workspace = true, public = true }
tokio = { workspace = true, public = true }
tracing = { workspace = true }❌ Wrong Section
# WRONG - serde should be in "Public third-party"
[dependencies]
# Private third-party dependencies
serde = { workspace = true, public = true }❌ No Alignment
# WRONG - inconsistent spacing
hash-graph-types = { workspace = true, public = true }
hashql-core = { workspace = true, public = true }---
Quick Checklist
When reviewing Cargo.toml:
- [ ] All 4 section comments present (even if empty)
- [ ] Dependencies in correct section (public/private, workspace/third-party)
- [ ]
public = truefor all public API dependencies - [ ]
workspace = truefor all dependencies - [ ] Alignment within each section
- [ ] No version numbers in package Cargo.toml
- [ ] Features specified at package level (not workspace)
---
Related
- workspace-setup.md - Managing workspace root
- package-dependencies.md - Section structure details
- SKILL.md - Overview and quick reference
Package Dependencies Guide
Complete guide for managing dependencies in package Cargo.toml files.
---
The 4-Section Structure
Every package Cargo.toml must organize dependencies into exactly 4 sections:
[dependencies]
# Public workspace dependencies
hash-graph-types = { workspace = true, public = true }
hashql-core = { workspace = true, public = true }
# Public third-party dependencies
serde = { workspace = true, public = true, features = ["derive"] }
tokio = { workspace = true, public = true }
smallvec = { workspace = true, public = true }
# Private workspace dependencies
error-stack = { workspace = true }
hash-codec = { workspace = true }
# Private third-party dependencies
tracing = { workspace = true }
regex = { workspace = true }
derive_more = { workspace = true, features = ["debug", "from"] }Section Order (Always)
1. Public workspace dependencies - Workspace crates in public API 2. Public third-party dependencies - External crates in public API 3. Private workspace dependencies - Workspace crates used internally 4. Private third-party dependencies - External crates used internally
Empty Sections
Keep section comments even when empty:
[dependencies]
# Public workspace dependencies
# Public third-party dependencies
serde = { workspace = true, public = true }
# Private workspace dependencies
# Private third-party dependencies
tracing = { workspace = true }See hashql-core/Cargo.toml for example.
---
Public vs Private Dependencies
What is public = true?
Use public = true when a dependency appears in your public API:
- Return types in public functions
- Public struct fields
- Re-exported types
- Generic trait bounds on public items
When to Use public = true
✅ Use public = true:
// Dependency appears in public signature
pub fn get_entity() -> EntityType { ... } // EntityType = public
// Dependency in public struct field
pub struct Store {
pub entities: Vec<EntityType>, // EntityType = public
}
// Re-exported
pub use serde::Serialize; // serde = public❌ Don't use public = true:
// Only used internally
fn internal_helper() -> EntityType { ... } // EntityType can be private
// Private field
pub struct Store {
entities: Vec<EntityType>, // EntityType can be private (private field)
}
// Only used in function bodies
pub fn process() {
let data = serde_json::to_string(&x); // serde_json can be private
}Public Dependency Examples
[dependencies]
# Public - these appear in public API
serde = { workspace = true, public = true }
tokio = { workspace = true, public = true }
hash-codec = { workspace = true, public = true }
# Private - only used internally
tracing = { workspace = true }
regex = { workspace = true }---
Adding Dependencies
Step 1: Determine Section
Ask yourself:
1. Is it a workspace member or external crate? 2. Does it appear in my public API?
This gives you one of 4 sections:
- Public + workspace → Section 1
- Public + external → Section 2
- Private + workspace → Section 3
- Private + external → Section 4
Step 2: Add to Appropriate Section
[dependencies]
# Public workspace dependencies
my-workspace-crate = { workspace = true, public = true }
# Public third-party dependencies
serde = { workspace = true, public = true, features = ["derive"] }
# Private workspace dependencies
error-stack = { workspace = true }
# Private third-party dependencies
tracing = { workspace = true }Step 3: Add Features (if needed)
# Enable specific features
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "signal"] }
serde = { workspace = true, public = true, features = ["derive"] }---
Alignment and Formatting
Align = signs within each section for readability:
Good Alignment
# Public workspace dependencies
hash-graph-types = { workspace = true, public = true }
hashql-core = { workspace = true, public = true }
hashql-diagnostics = { workspace = true, public = true }
# Public third-party dependencies
anstyle = { workspace = true, public = true }
foldhash = { workspace = true, public = true }
hashbrown = { workspace = true, public = true }Bad Alignment
# Don't do this
hash-graph-types = { workspace = true, public = true }
hashql-core = { workspace = true, public = true }
hashql-diagnostics = { workspace = true, public = true }Use spaces (not tabs) to align the = within each section.
---
Features Configuration
Enabling Features
[dependencies]
# Enable specific features needed by this package
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
serde = { workspace = true, features = ["derive"] }Feature Dependencies
Features can depend on other features:
[features]
default = ["std"]
std = ["serde/std", "dep:tokio"]---
Optional Dependencies
For conditional compilation:
[dependencies]
# Optional dependencies
serde = { workspace = true, optional = true, features = ["derive"] }
tokio = { workspace = true, optional = true }
[features]
# Activate optional dependencies via features
serde = ["dep:serde"]
async = ["dep:tokio", "tokio/rt"]Note: Optional dependencies still follow the 4-section structure.
---
dev-dependencies
Dev dependencies don't need the 4-section structure:
[dev-dependencies]
insta = { workspace = true }
proptest = { workspace = true }
rstest = { workspace = true }
test-strategy = { workspace = true }Just list them alphabetically, all with workspace = true.
---
Common Patterns
Adding a Workspace Member (Public)
[dependencies]
# Public workspace dependencies
my-crate = { workspace = true, public = true }Adding External Crate (Private)
[dependencies]
# Private third-party dependencies
regex = { workspace = true }Adding with Features
[dependencies]
# Private third-party dependencies
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }Optional + Public
[dependencies]
# Public third-party dependencies
serde = { workspace = true, public = true, optional = true, features = ["derive"] }
[features]
serde = ["dep:serde"]---
Related
- workspace-setup.md - Adding to workspace root
- examples-reference.md - Real examples from HASH
- SKILL.md - Overview and quick reference
Workspace Setup Guide
Complete guide for managing dependencies in the workspace root Cargo.toml.
---
Checking Existing Dependencies
Before adding a new dependency, check if it already exists:
grep "^my-crate" Cargo.tomlOr search within the workspace.dependencies section:
grep -A 1 "^\[workspace.dependencies\]" Cargo.toml | grep "my-crate"---
Adding External Crates
All external crates must be defined in workspace root [workspace.dependencies]:
Basic External Dependency
[workspace.dependencies]
# External dependencies
serde = { version = "1.0.228", default-features = false }
tokio = { version = "1.47.1", default-features = false }
regex = { version = "1.11.1", default-features = false }With Features (at workspace level)
[workspace.dependencies]
# When you need features enabled everywhere
derive_more = { version = "1.0.0", default-features = false, features = ["debug", "from"] }Note: Usually better to enable features at package level for granular control.
---
Version Specifiers
HASH uses caret version specifiers (e.g., 1.0.228 = ^1.0.228) for reproducible builds with Cargo.lock:
✅ Correct:
serde = { version = "1.0.228", default-features = false }
tokio = { version = "1.47.1", default-features = false }❌ Wrong:
serde = { version = "=1.0.228", default-features = false } # Exact pinning (not needed)
tokio = "1.47" # No shorthand
serde = { version = "1.0", default-features = false } # Too vague---
Default Features
Always disable default features at workspace level:
[workspace.dependencies]
# Disable defaults - enable features where needed
tokio = { version = "=1.47.1", default-features = false }
serde = { version = "=1.0.228", default-features = false }
regex = { version = "=1.11.1", default-features = false }Then enable specific features in package Cargo.toml:
# In package Cargo.toml
[dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
serde = { workspace = true, features = ["derive"] }Note: Workspace root should have default-features = false, but package level can override with specific features.
Why Disable Defaults?
- Smaller binaries - Only include what you need
- Faster compile times - Less code to compile
- Explicit dependencies - Clear what features each package uses
- Avoid bloat - Default features often include unnecessary functionality
---
Workspace Members
For internal crates (workspace members), use path references:
[workspace.dependencies]
# Workspace members
error-stack.path = "libs/error-stack"
hash-codec.path = "libs/@local/codec"
hash-graph-types.path = "libs/@local/hash-graph-types"
hashql-core.path = "libs/@local/hashql/core"Note: Use relative paths from workspace root.
---
Organizing Workspace Dependencies
Group related dependencies with comments:
[workspace.dependencies]
# Core error handling
error-stack = { path = "libs/error-stack" }
# Async runtime
tokio = { version = "1.47.1", default-features = false }
tokio-util = { version = "0.7.13", default-features = false }
# Serialization
serde = { version = "1.0.228", default-features = false }
serde_json = { version = "1.0.138", default-features = false }
# Database
postgres = { version = "0.19.9", default-features = false }
postgres-types = { version = "0.2.8", default-features = false }---
Finding Latest Versions
# Check crates.io for latest version
cargo search my-crate --limit 1
# Or use cargo-edit (if installed)
cargo add my-crate --dry-run---
Common Patterns
Adding a Popular Crate
[workspace.dependencies]
# Add to appropriate section
tracing = { version = "0.1.41", default-features = false }Adding with Specific Features (workspace-wide)
[workspace.dependencies]
# When all packages need the same features
uuid = { version = "1.11.0", default-features = false, features = ["v4", "serde"] }Adding Workspace Member
[workspace.dependencies]
my-new-crate.path = "libs/@local/my-new-crate"---
Related
- package-dependencies.md - Adding to package Cargo.toml
- examples-reference.md - Real examples from HASH
- Workspace Cargo.toml - Root configuration