---
title: "cargo-machete vs cargo-udeps: Deps Não Usadas | Rust Brasil"
url: "https://rustlang.com.br/blog/cargo-machete-cargo-udeps-dependencias-nao-usadas-2026/"
markdown_url: "https://rustlang.com.br/blog/cargo-machete-cargo-udeps-dependencias-nao-usadas-2026.MD"
description: "Encontre dependências não usadas em Rust com cargo-machete e cargo-udeps. Guia com instalação, workspaces, falsos positivos, CI e impacto no build na prática."
date: "2026-08-08"
author: "Equipe Rust Brasil"
---

# cargo-machete vs cargo-udeps: Deps Não Usadas | Rust Brasil

Encontre dependências não usadas em Rust com cargo-machete e cargo-udeps. Guia com instalação, workspaces, falsos positivos, CI e impacto no build na prática.


**Para encontrar dependências não usadas em um projeto Rust, rode `cargo machete` para uma varredura rápida e confirme os achados com `cargo +nightly udeps` antes de apagar qualquer linha do `Cargo.toml`.** As duas ferramentas respondem à mesma pergunta — “esta crate ainda serve para alguma coisa?” — usando estratégias diferentes: uma analisa o código-fonte, a outra se apoia na compilação real.

Essa limpeza raramente aparece em roadmap, mas paga bem. Cada dependência esquecida continua sendo resolvida pelo Cargo, baixada na CI, compilada, cacheada e auditada. Ela aumenta o tempo de build, o tamanho do `Cargo.lock`, a superfície de supply chain e o custo de revisar advisories que não afetam o produto em nada.

Este guia mostra como instalar e usar `cargo-machete` e `cargo-udeps`, como interpretar cada relatório, como lidar com workspaces e features, quais são os falsos positivos clássicos e como colocar a verificação na CI sem transformá-la em fonte de ruído.

## Resposta rápida: qual ferramenta usar

| Situação | Ferramenta indicada | Por quê |
|---|---|---|
| Check rápido no dia a dia ou em pull request | **cargo-machete** | Roda em segundos, não exige nightly nem build completo |
| Confirmar um caso duvidoso antes de remover | **cargo-udeps** | Usa o compilador, reduzindo palpite sobre uso real |
| Workspace grande com muitas crates | **As duas** | Machete varre tudo rápido; udeps aprofunda no pacote suspeito |
| Projeto preso a uma toolchain estável na CI | **cargo-machete** | udeps precisa de nightly instalada no job |
| Auditoria antes de um release importante | **As duas** | Custo maior é aceitável quando o objetivo é enxugar o artefato |

Nenhuma das duas decide sozinha. Elas produzem **candidatos**; a remoção final é uma decisão de engenharia validada por compilação, testes e features.

## Por que dependências mortas se acumulam

Um `Cargo.toml` cresce por caminhos previsíveis:

- um protótipo virou produção e ninguém revisitou as crates iniciais;
- uma biblioteca de HTTP foi trocada por outra, mas a antiga ficou declarada;
- um utilitário de datas foi substituído por `std`;
- um teste temporário puxou uma dependência que continuou no `[dependencies]` em vez de `[dev-dependencies]`;
- uma feature experimental foi revertida no código, não no manifesto;
- um refactor removeu o último `use` de uma crate sem tocar no manifesto.

O compilador não reclama. Rust avisa sobre imports não usados dentro de um arquivo, mas não sobre uma crate declarada e nunca referenciada. É exatamente essa lacuna que `cargo-machete` e `cargo-udeps` preenchem.

O efeito colateral aparece devagar: builds mais lentos, cache maior, dependências transitivas desnecessárias e relatórios de segurança apontando crates que o produto sequer usa. Para o contexto mais amplo dessa disciplina, veja nosso guia de [segurança e supply chain com cargo-deny e SBOM](/blog/rust-seguranca-supply-chain-cargo-deny-sbom-2026/).

## cargo-machete: a varredura rápida

O `cargo-machete` percorre o `Cargo.toml` e o código-fonte procurando referências a cada dependência declarada. Como não depende de compilação completa, ele é rápido o suficiente para rodar em qualquer pull request.

### Instalação e primeira execução

```bash
cargo install cargo-machete --locked
cargo machete --version
```

Na raiz do projeto:

```bash
cargo machete
```

A saída lista, por pacote, as dependências que a ferramenta não conseguiu associar a nenhum uso no código. Um exemplo ilustrativo:

```text
cargo-machete found the following unused dependencies in /projeto:
minha-api -- minha-api/Cargo.toml:
	chrono
	once_cell
```

Isso significa: “o manifesto declara `chrono` e `once_cell`, mas eu não encontrei uso delas no código-fonte deste pacote”. É uma hipótese forte, não um veredito.

### Consultando um workspace inteiro

Em um monorepo, a execução na raiz percorre os membros do workspace e agrupa o resultado por pacote. Isso combina bem com a organização descrita no guia de [workspaces Cargo e monorepos](/blog/cargo-workspaces-monorepos-rust-2026/): você descobre rapidamente qual crate acumulou manifesto além do necessário.

Um fluxo prático:

```bash
cargo machete > /tmp/machete-antes.txt
# ... remova dependências, ajuste features ...
cargo machete > /tmp/machete-depois.txt
diff -u /tmp/machete-antes.txt /tmp/machete-depois.txt
```

### Ignorando falsos positivos de forma explícita

Quando uma dependência é legítima mas a análise não consegue enxergar o uso — o caso típico é uma crate consumida apenas por macro, build script ou reexport — o `cargo-machete` permite declarar a exceção no próprio manifesto, em vez de espalhar comentários pelo repositório:

```toml
[package.metadata.cargo-machete]
ignored = ["crate-usada-por-macro"]
```

Essa marcação é melhor do que silenciar a ferramenta inteira. Ela documenta a decisão no lugar certo, sobrevive a trocas de time e pode ser revisada em code review. Confirme a chave exata suportada pela versão instalada com `cargo machete --help`.

## cargo-udeps: a confirmação pelo compilador

O `cargo-udeps` responde à mesma pergunta por outro caminho. Em vez de procurar referências no texto, ele se apoia na compilação para observar quais dependências realmente participaram do build. Por isso ele é mais preciso — e mais caro.

### Instalação e execução

```bash
rustup toolchain install nightly
cargo install cargo-udeps --locked
cargo +nightly udeps
```

A exigência de nightly costuma gerar hesitação, mas não implica adotar nightly no produto. Você pode manter `stable` como toolchain oficial e instalar `nightly` apenas no job de auditoria ou na máquina de quem faz a limpeza.

Variações úteis:

```bash
cargo +nightly udeps --all-targets
cargo +nightly udeps -p minha-api
cargo +nightly udeps --all-features
cargo +nightly udeps --no-default-features
```

O `--all-targets` é especialmente importante: sem ele, dependências usadas somente em testes, benchmarks ou exemplos podem parecer inúteis.

### Quando o resultado das duas ferramentas diverge

Divergência é informação, não defeito. Interprete assim:

| Machete | udeps | Leitura provável |
|---|---|---|
| Aponta | Aponta | Candidato forte para remoção |
| Aponta | Não aponta | Uso invisível ao texto: macro, build script, reexport, cfg |
| Não aponta | Aponta | Referência existe no código, mas não entra no build atual (feature ou target desativado) |
| Não aponta | Não aponta | Dependência em uso normal |

O segundo e o terceiro caso são os mais instrutivos. Eles costumam revelar que o projeto tem código morto atrás de uma feature, ou que uma crate só é exercida em um target específico.

## Falsos positivos clássicos

Antes de apagar qualquer linha, confira estes cenários:

**Build scripts.** Uma crate usada apenas em `build.rs` pertence a `[build-dependencies]`. Se ela está no lugar errado, o relatório pode ficar confuso nos dois sentidos.

**Macros e derives.** Uma dependência puxada por `#[derive(...)]` de outra crate pode não aparecer como `use` explícito. É o caso mais comum de falso positivo do machete.

**Reexports.** Uma biblioteca que faz `pub use outra_crate::Tipo;` expõe a dependência como parte da API pública, mesmo sem chamar métodos dela. Removê-la é uma quebra de contrato — assunto tratado no guia de [cargo-semver-checks e SemVer na CI](/blog/cargo-semver-checks-rust-api-ci-2026/).

**Código atrás de `cfg`.** Uma crate usada somente em Windows, somente em `target_arch` específico ou somente com `#[cfg(feature = "...")]` pode sumir do build padrão. Reveja o guia de [compilação condicional com cfg e features](/blog/compilacao-condicional-rust-cfg-features/) quando o relatório parecer estranho.

**Dev-dependencies.** Sem `--all-targets`, testes de integração, benchmarks com [Criterion](/ecossistema/criterion/) e exemplos não entram na conta.

**Features opcionais.** Uma dependência opcional pode existir justamente para ser ativada por quem consome a biblioteca. Ela é “não usada” no build padrão e ainda assim essencial ao produto.

## Checklist de remoção segura

Trate cada remoção como uma mudança de código, não como faxina de manifesto:

1. rode `cargo machete` e anote os candidatos;
2. confirme com `cargo +nightly udeps --all-targets`;
3. verifique se a crate aparece em `build.rs`, macros, reexports ou blocos `cfg`;
4. remova **uma** dependência por vez;
5. rode `cargo check --all-targets` e `cargo test` (ou [cargo-nextest](/blog/cargo-nextest-testes-rust-2026/));
6. compile também com `--all-features` e `--no-default-features`;
7. se o projeto suporta outros sistemas, compile para os targets relevantes — veja [cargo-zigbuild para cross-compilation](/blog/cargo-zigbuild-cross-compile-rust-2026/);
8. rode [Clippy](/ecossistema/clippy/) e `cargo fmt --check`;
9. confirme o efeito no `Cargo.lock` e no binário;
10. registre no commit por que a dependência saiu.

O passo 4 parece burocrático, mas evita a situação clássica: cinco remoções juntas, build quebrado e ninguém sabe qual delas causou o problema.

## Medindo o ganho real

Remover dependências é satisfatório, mas o benefício precisa ser verificado. Antes e depois da limpeza:

```bash
cargo clean
/usr/bin/time -v cargo build --release --locked
```

Compare também o número de crates resolvidas:

```bash
cargo tree | wc -l
cargo tree -e features | wc -l
```

E o artefato final, com o método descrito no guia de [cargo-bloat para reduzir o tamanho do binário](/blog/cargo-bloat-reduzir-tamanho-binario-rust-2026/):

```bash
cargo bloat --release --crates
```

Nem toda remoção muda o binário. O linker costuma descartar código não referenciado, então uma dependência morta pode custar tempo de compilação sem custar bytes. Por isso as perguntas devem ser separadas:

| Pergunta | Ferramenta |
|---|---|
| Esta dependência ainda é usada? | `cargo-machete`, `cargo-udeps` |
| O build ficou mais rápido? | build limpo cronometrado, `cargo build --timings` |
| O binário ficou menor? | `cargo-bloat` |
| Genéricos estão gerando código demais? | [`cargo-llvm-lines`](/blog/cargo-llvm-lines-monomorfizacao-rust-2026/) |
| O gargalo é link, não compilação? | [`mold`](/blog/mold-linker-rust-compilacao-rapida-2026/) |
| O gargalo é recompilação repetida na CI? | [`sccache`](/blog/sccache-rust-cache-compilacao-ci-2026/) |

Se o objetivo principal é reduzir tempo de build, comece pelo diagnóstico do guia de [como otimizar o tempo de compilação em Rust](/blog/rust-tempo-compilacao-otimizar-build-2026/). Dependência morta é uma causa possível, não a única.

## Integrando na CI sem gerar ruído

Um job leve com `cargo-machete` funciona bem como check contínuo:

```yaml
name: deps

on:
  pull_request:
  workflow_dispatch:

jobs:
  unused-deps:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Instalar Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Instalar cargo-machete
        run: cargo install cargo-machete --locked

      - name: Verificar dependências não usadas
        run: cargo machete
```

O mesmo desenho funciona em Gitea Actions quando o runner oferece actions compatíveis — lembrando que este site mantém workflows nos dois formatos e eles precisam permanecer alinhados. Para o pipeline completo, veja o guia de [CI/CD em projetos Rust](/artigos/ci-cd-rust/).

Recomendações práticas:

- comece com o job **informativo**; promova a obrigatório depois que os falsos positivos estiverem documentados em `[package.metadata.cargo-machete]`;
- deixe `cargo-udeps` em um job **agendado** (semanal) ou manual, já que exige nightly e build completo;
- pine a versão da ferramenta ou use cache para não pagar `cargo install` em todo job;
- nunca adicione um `ignore` global sem justificativa — a exceção deve ser nominal e revisável.

## Por que isso aparece em entrevista

Saber limpar dependências é um sinal de maturidade operacional. Em entrevistas para posições de backend, plataforma e infraestrutura, é comum pedirem que o candidato explique como reduziria o tempo de build de um serviço Rust. Responder “eu removeria dependências” é fraco; responder com um método — machete para triagem, udeps para confirmação, medição antes/depois, atenção a features e targets, exceções documentadas — mostra que a pessoa opera o projeto, não apenas escreve código.

Esse tipo de competência aparece em vagas de plataforma, ferramentas internas e times que mantêm bibliotecas compartilhadas. Acompanhe as [vagas Rust](/vagas/) e as [empresas que usam Rust no Brasil](/empresas/) para ver como esses requisitos são descritos, e o [plano de estudos sênior](/carreira/plano-estudos-senior/) para encaixar tooling na trilha de crescimento.

A disciplina também não é exclusiva de Rust. Times que trabalham com Go enfrentam a mesma tensão entre módulos declarados e módulos realmente usados; o portal <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Golang Brasil</a> cobre o lado do ecossistema Go. A diferença é que, em Rust, o custo de uma dependência esquecida tende a ser mais visível no tempo de compilação.

## Perguntas frequentes

### Como encontrar dependências não usadas em Rust?

Rode `cargo machete` para uma varredura rápida e `cargo +nightly udeps --all-targets` para confirmar. Trate o resultado como lista de candidatos e valide cada remoção com build e testes.

### Qual a diferença entre cargo-machete e cargo-udeps?

`cargo-machete` analisa manifesto e código-fonte, sendo rápido e compatível com toolchain estável. `cargo-udeps` se apoia na compilação e exige nightly, entregando mais precisão a um custo maior de tempo.

### cargo-udeps precisa mesmo de nightly?

Sim, ele é executado como `cargo +nightly udeps`. Você pode instalar a toolchain nightly apenas para o job de auditoria, mantendo `stable` como toolchain do projeto.

### Remover dependências deixa o binário menor?

Nem sempre. O linker já descarta código não referenciado, então o ganho mais frequente é em tempo de build, cache e superfície de auditoria. Confirme com `cargo-bloat` antes de prometer redução de tamanho.

### Como lidar com falsos positivos?

Documente a exceção em `[package.metadata.cargo-machete]` com a lista `ignored`, explicando no commit por que a dependência é necessária (macro, build script, reexport ou feature opcional).

## Conclusão

`cargo-machete` e `cargo-udeps` não competem: eles se complementam. O primeiro é o filtro barato que cabe em toda pull request; o segundo é a confirmação cara que vale antes de mexer no manifesto. Juntos, transformam “acho que essa crate não é mais usada” em uma decisão apoiada por evidência.

O fluxo recomendado é simples: **varra com machete, confirme com udeps, remova uma dependência por vez, valide com todas as features e targets relevantes e meça o efeito no build e no binário**. Documente as exceções onde elas fazem sentido — no `Cargo.toml` — e deixe a CI lembrar o time quando o manifesto começar a crescer sozinho de novo.

Para continuar a limpeza, combine este guia com [cargo-bloat](/blog/cargo-bloat-reduzir-tamanho-binario-rust-2026/), [cargo-llvm-lines](/blog/cargo-llvm-lines-monomorfizacao-rust-2026/) e as [ferramentas essenciais do Cargo](/artigos/cargo-ferramentas-essenciais/). Cada uma responde a uma pergunta diferente sobre o mesmo projeto — e é essa separação que evita otimizar o número errado.
