---
title: "Gerenciamento de Dependências Rust: Cargo | Rust Brasil"
url: "https://rustlang.com.br/artigos/gerenciamento-dependencias/"
markdown_url: "https://rustlang.com.br/artigos/gerenciamento-dependencias.MD"
description: "Guia completo de gerenciamento de dependências em Rust com Cargo: Cargo.toml, features, workspaces, versioning e crates.io."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Gerenciamento de Dependências Rust: Cargo | Rust Brasil

Guia completo de gerenciamento de dependências em Rust com Cargo: Cargo.toml, features, workspaces, versioning e crates.io.


## Introdução

O Cargo é muito mais do que um gerenciador de pacotes — é o sistema de build, gerenciador de dependências, executor de testes e publicador de bibliotecas do ecossistema Rust, tudo em uma ferramenta. Dominar o Cargo é essencial para qualquer projeto Rust que vá além de um simples exercício.

Neste artigo, vamos explorar em profundidade como o Cargo gerencia dependências, desde a sintaxe do `Cargo.toml` até recursos avançados como workspaces, features condicionais e estratégias de atualização segura.

## O Problema: Dependências Desorganizadas

### Não Faça Isso: Versões Imprecisas

```toml
# ERRADO: Sem Cargo.lock no repositório (para binários)
# Cargo.toml
[dependencies]
serde = "*"            # Qualquer versão — pode quebrar a qualquer momento
reqwest = "0"          # Aceita 0.x.y, incluindo mudanças incompatíveis
tokio = ">=1.0.0"      # Aceita 2.0.0 quando sair, mesmo sendo breaking change
```

### Não Faça Isso: Dependências Desnecessárias

```toml
# ERRADO: Puxar crates inteiras para usar uma função
[dependencies]
chrono = "0.4"         # Só precisa de timestamp Unix? Use std::time
regex = "1"            # Só precisa de split? Use str::split
rand = "0.8"           # Só precisa de um ID? Use uuid
num = "0.4"            # Só precisa de abs()? Use i32::abs()
```

### Não Faça Isso: Features Ativadas sem Necessidade

```toml
# ERRADO: Ativa TODAS as features, incluindo as que não usa
[dependencies]
tokio = { version = "1", features = ["full"] }  # Inclui io, fs, net, process, signal...
reqwest = { version = "0.12", features = ["json", "cookies", "gzip", "brotli", "stream"] }
```

## A Solução: Cargo.toml Bem Configurado

### Faça Isso: Versionamento Semântico Correto

```toml
# Cargo.toml
[dependencies]
# Versão exata (para dependências críticas)
serde = "=1.0.217"

# Patch updates apenas (padrão com ^): aceita 1.0.x
serde = "1.0.217"       # Equivalente a "^1.0.217"

# Minor updates: aceita 1.x.y onde x >= 0
serde = "1"             # Equivalente a "^1.0.0"

# Tilde: mais restritivo, apenas patches
serde = "~1.0.217"      # Aceita >= 1.0.217, < 1.1.0

# Para crates pré-1.0 (0.x), o minor é tratado como major
rand = "0.8"            # Aceita >= 0.8.0, < 0.9.0 (NÃO aceita 0.9)
```

**Regra de ouro**: Use a forma padrão `"1.0"` para a maioria das dependências. O operador `^` (implícito) é seguro com SemVer.

### Faça Isso: Features Mínimas

```toml
# Cargo.toml — ative apenas o necessário
[dependencies]
# Tokio: apenas as features que você usa
tokio = { version = "1", features = ["rt-multi-thread", "macros", "net"] }

# Serde: derive é quase sempre necessário
serde = { version = "1", features = ["derive"] }

# Reqwest: apenas JSON e TLS
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }

# SQLx: runtime e driver específicos
sqlx = { version = "0.8", default-features = false, features = [
    "runtime-tokio",
    "postgres",
    "macros",
] }
```

Desabilite `default-features` quando quiser controle total:

```toml
# Sem features padrão, apenas o que você precisa
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
```

### Faça Isso: Dependências por Uso

```toml
# Cargo.toml

# Dependências principais (usadas em src/)
[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

# Dependências apenas para testes
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
tempfile = "3"
mockall = "0.13"
pretty_assertions = "1"

# Dependências apenas para build scripts
[build-dependencies]
cc = "1"
prost-build = "0.13"

# Dependências opcionais (ativadas por features)
[dependencies.tracing]
version = "0.1"
optional = true
```

### Features do Seu Próprio Crate

```toml
# Cargo.toml

[features]
default = ["json"]

# Feature que ativa funcionalidade extra
json = ["dep:serde", "dep:serde_json"]
logging = ["dep:tracing"]
full = ["json", "logging"]

[dependencies]
serde = { version = "1", features = ["derive"], optional = true }
serde_json = { version = "1", optional = true }
tracing = { version = "0.1", optional = true }
```

```rust
// src/lib.rs — código condicional por feature

pub fn processar(dados: &str) -> String {
    #[cfg(feature = "logging")]
    tracing::info!("Processando {} bytes", dados.len());

    dados.to_uppercase()
}

#[cfg(feature = "json")]
pub mod json {
    use serde::{Deserialize, Serialize};

    #[derive(Serialize, Deserialize)]
    pub struct Resposta {
        pub mensagem: String,
        pub status: u16,
    }

    pub fn parse(input: &str) -> Result<Resposta, serde_json::Error> {
        serde_json::from_str(input)
    }
}
```

## Workspaces: Monorepo com Cargo

Para projetos maiores, organize em workspace:

```
meu-projeto/
├── Cargo.toml          # Workspace root
├── crates/
│   ├── core/
│   │   ├── Cargo.toml
│   │   └── src/lib.rs
│   ├── api/
│   │   ├── Cargo.toml
│   │   └── src/main.rs
│   └── cli/
│       ├── Cargo.toml
│       └── src/main.rs
```

```toml
# Cargo.toml (raiz do workspace)
[workspace]
resolver = "2"
members = [
    "crates/core",
    "crates/api",
    "crates/cli",
]

# Dependências compartilhadas entre membros
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
thiserror = "2"

# Metadados compartilhados
[workspace.package]
version = "0.1.0"
edition = "2024"
authors = ["Equipe Rust Brasil"]
license = "MIT"
```

```toml
# crates/core/Cargo.toml
[package]
name = "meu-projeto-core"
version.workspace = true
edition.workspace = true

[dependencies]
serde.workspace = true         # Usa a versão do workspace
thiserror.workspace = true
```

```toml
# crates/api/Cargo.toml
[package]
name = "meu-projeto-api"
version.workspace = true
edition.workspace = true

[dependencies]
meu-projeto-core = { path = "../core" }   # Dependência local
serde.workspace = true
tokio.workspace = true
```

Vantagens do workspace:
- **Um `Cargo.lock`** para todo o projeto — versões consistentes
- **Compilação compartilhada** — dependências comuns são compiladas uma vez
- **Dependências centralizadas** — atualize a versão em um lugar só

## Gerenciamento de Lockfile

### Para Bibliotecas: Não commite `Cargo.lock`

```gitignore
# .gitignore — para bibliotecas
Cargo.lock
```

Bibliotecas devem ser testadas com as versões mais recentes compatíveis.

### Para Aplicações: Sempre commite `Cargo.lock`

```gitignore
# .gitignore — para aplicações
# NÃO ignore Cargo.lock!
# Isso garante builds reproduzíveis
```

### Atualizando Dependências com Segurança

```bash
# Ver dependências desatualizadas
cargo outdated

# Atualizar dentro das restrições do Cargo.toml
cargo update

# Atualizar uma crate específica
cargo update -p serde

# Ver a árvore de dependências
cargo tree

# Encontrar duplicatas
cargo tree --duplicates

# Por que uma dependência está incluída?
cargo tree --invert --package openssl-sys
```

## Guia Passo a Passo: Auditoria de Dependências

### Passo 1: Analise a Árvore

```bash
# Visualizar toda a árvore
cargo tree

# Output exemplo:
# meu-app v0.1.0
# ├── axum v0.8.1
# │   ├── axum-core v0.5.0
# │   │   ├── http v1.2.0
# │   │   └── ...
# ├── serde v1.0.217
# └── tokio v1.42.0
```

### Passo 2: Identifique Duplicatas

```bash
cargo tree --duplicates

# Se houver duas versões de uma crate, considere alinhar
```

### Passo 3: Verifique Vulnerabilidades

```bash
cargo install cargo-audit
cargo audit
```

### Passo 4: Verifique Licenças

```bash
cargo install cargo-deny
cargo deny check licenses
```

### Passo 5: Atualize com Cuidado

```bash
# 1. Crie um branch
# git checkout -b atualizar-deps

# 2. Atualize
cargo update

# 3. Rode todos os testes
cargo test

# 4. Verifique se tudo ainda funciona
cargo clippy

# 5. Commite o Cargo.lock atualizado
```

## Armadilhas Comuns

### 1. Não Travar Versões em Aplicações

```toml
# ERRADO para aplicações: depender de ranges amplos sem Cargo.lock
[dependencies]
serde = "1"  # Sem Cargo.lock commitado, cada build pode usar versão diferente

# CORRETO: Commite o Cargo.lock para builds reproduzíveis
# E use `cargo update` periodicamente para atualizar
```

### 2. Features Conflitantes

```toml
# Cuidado: se duas crates ativam features diferentes de uma mesma dependência,
# o Cargo unifica (union) as features

# Crate A depende de: tokio = { features = ["rt"] }
# Crate B depende de: tokio = { features = ["fs"] }
# Resultado: tokio é compilado com ["rt", "fs"]
# Isso pode causar tempos de compilação maiores que o esperado
```

### 3. Usar `path` em Dependências Publicadas

```toml
# ERRADO: path dependencies não funcionam quando publicadas no crates.io
[dependencies]
minha-lib = { path = "../minha-lib" }

# CORRETO: Para publicação, use versão do crates.io
[dependencies]
minha-lib = "1.0"

# Para desenvolvimento local, use [patch]
[patch.crates-io]
minha-lib = { path = "../minha-lib" }
```

### 4. Dependência Circular

```toml
# ERRADO: Cargo não permite dependências circulares
# crate-a depende de crate-b
# crate-b depende de crate-a  → ERRO!

# CORRETO: Extraia a parte comum para um terceiro crate
# crate-common (sem dependências dos outros)
# crate-a depende de crate-common
# crate-b depende de crate-common
```

### 5. Ignorar Feature `resolver = "2"`

```toml
# Para workspaces e edition 2021+, sempre use resolver 2
[workspace]
resolver = "2"

# Resolver 2 trata features de dev-dependencies separadamente,
# evitando que features de teste contaminem a compilação normal
```

## Exemplo do Mundo Real: Cargo.toml Completo

```toml
[package]
name = "minha-api"
version = "0.1.0"
edition = "2024"
authors = ["Equipe Rust Brasil <contato@rustbrasil.dev>"]
description = "API REST de exemplo com boas práticas de Cargo"
license = "MIT"
repository = "https://github.com/rustlang-br/minha-api"
readme = "README.md"
keywords = ["api", "rest", "rust"]
categories = ["web-programming::http-server"]

[dependencies]
# Web framework
axum = { version = "0.8", features = ["macros"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal"] }
tower = { version = "0.5", features = ["limit", "timeout"] }
tower-http = { version = "0.6", features = ["cors", "trace", "compression-gzip"] }

# Serialização
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# Banco de dados
sqlx = { version = "0.8", features = [
    "runtime-tokio",
    "postgres",
    "macros",
    "migrate",
], default-features = false }

# Observabilidade
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }

# Erros
thiserror = "2"
anyhow = "1"

# Configuração
dotenvy = "0.15"

[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
reqwest = { version = "0.12", features = ["json"] }
tempfile = "3"
tokio = { version = "1", features = ["test-util"] }

[[bench]]
name = "api_benchmarks"
harness = false

[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
strip = true

[profile.dev]
opt-level = 0
debug = true

[profile.dev.package."*"]
opt-level = 2  # Otimiza dependências mesmo em debug (compilação mais lenta, mas runtime mais rápido)
```

## Checklist de Gerenciamento de Dependências

1. **SemVer correto** — Use `"1.0"` (com `^` implícito) para a maioria dos casos
2. **Features mínimas** — Ative apenas o que você usa
3. **`Cargo.lock` no git** — Para aplicações, sempre commite
4. **`cargo audit`** regularmente — Verifique vulnerabilidades
5. **`cargo outdated`** — Mantenha dependências atualizadas
6. **`cargo tree`** — Entenda sua árvore de dependências
7. **Workspaces** — Para projetos com múltiplos crates
8. **`resolver = "2"`** — Sempre para edition 2021+
9. **`dev-dependencies` separadas** — Não misture com dependências de produção
10. **Revise antes de adicionar** — Cada dependência é um risco e um custo

---

## Veja Também

- [Instalação: Cargo](/instalacao/cargo/) — Primeiros passos com o Cargo
- [Erros: Feature Not Found](/erros/cargo-feature-not-found/) — Como resolver erros de features
- [CI/CD para Projetos Rust](/artigos/ci-cd-rust/) — Automatize verificação de dependências
- [Segurança em Rust](/artigos/seguranca-rust/) — Audite dependências com cargo-audit
- [Documentação em Rust](/artigos/documentacao-rust/) — Metadados do Cargo.toml para docs.rs

---

Veja como o gerenciamento de dependências funciona em outros ecossistemas:

- <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go Modules: gerenciamento de dependências no Go com go.mod e go.sum</a>
- <a href="https://python.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'python.dev.br' })">pip, Poetry e pyproject.toml: dependências em Python moderno</a>
- <a href="https://kotlin.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'kotlin.dev.br' })">Gradle e Kotlin: gerenciamento de dependências e build na JVM</a>
