<h2>O que são Workspaces no Cargo?</h2>
<p>Um workspace no Cargo é um mecanismo para organizar múltiplos pacotes Rust dentro de um único repositório, compartilhando dependências e configurações comuns. Diferente de um monorepo simples, workspaces oferecem otimizações na compilação, permitindo que crates (pacotes) evitem compilações redundantes de dependências já processadas. Quando você trabalha com projetos grandes, é comum ter uma biblioteca core, aplicações cliente, ferramentas CLI e módulos especializados — e é exatamente nesse cenário que workspaces brilham.</p>
<p>A estrutura de um workspace é definida em um arquivo <code>Cargo.toml</code> raiz que lista todos os membros. Cada membro é uma crate independente com seu próprio <code>Cargo.toml</code>, mas todos compartilham o mesmo <code>target/</code> para artefatos compilados. Isso economiza espaço em disco e tempo de build significativamente em projetos grandes.</p>
<h2>Estruturando seu Primeiro Workspace</h2>
<h3>Criando a Estrutura Base</h3>
<p>Comece criando um diretório para seu workspace e o arquivo <code>Cargo.toml</code> raiz:</p>
<pre><code class="language-toml">[workspace]
members = [
"core",
"cli",
"web_server",
]
resolver = "2"
[workspace.package]
version = "0.1.0"
edition = "2021"
authors = ["seu_nome"]</code></pre>
<p>Agora crie os diretórios das crates:</p>
<pre><code class="language-bash">mkdir -p core cli web_server
cargo init --lib core
cargo init --bin cli
cargo init --bin web_server</code></pre>
<h3>Estrutura de Diretórios Resultante</h3>
<pre><code>projeto_grande/
├── Cargo.toml # Arquivo raiz do workspace
├── Cargo.lock
├── target/ # Compartilhado entre todas as crates
├── core/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── cli/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
└── web_server/
├── Cargo.toml
└── src/
└── main.rs</code></pre>
<h2>Gerenciando Dependências em Workspaces</h2>
<h3>Dependências Compartilhadas</h3>
<p>O grande benefício dos workspaces é evitar recompilação de dependências comuns. Configure-as no <code>Cargo.toml</code> raiz:</p>
<pre><code class="language-toml">[workspace]
members = ["core", "cli", "web_server"]
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.35", features = ["full"] }
log = "0.4"</code></pre>
<p>Depois, em cada crate, referencie essas dependências sem repetir versões:</p>
<p><strong>core/Cargo.toml:</strong></p>
<pre><code class="language-toml">[package]
name = "core"
version.workspace = true
edition.workspace = true
[dependencies]
serde = { workspace = true }
log = { workspace = true }</code></pre>
<p><strong>cli/Cargo.toml:</strong></p>
<pre><code class="language-toml">[package]
name = "cli"
version.workspace = true
edition.workspace = true
[dependencies]
tokio = { workspace = true }
core = { path = "../core" }
log = { workspace = true }</code></pre>
<h3>Dependências Internas</h3>
<p>Uma crate pode depender de outra no mesmo workspace usando <code>path</code>. A grande vantagem: mudanças em <code>core</code> são imediatamente visíveis em <code>cli</code> sem publicar em crates.io. Exemplo prático no <code>cli/src/main.rs</code>:</p>
<pre><code class="language-rust">use core::models::User;
use log::info;
#[tokio::main]
async fn main() {
env_logger::init();
let user = User::new("Alice", 30);
info!("Usuário criado: {:?}", user);
}</code></pre>
<p>E em <code>core/src/lib.rs</code>:</p>
<pre><code class="language-rust">pub mod models;
pub struct User {
name: String,
age: u32,
}
impl User {
pub fn new(name: &str, age: u32) -> Self {
User {
name: name.to_string(),
age,
}
}
}</code></pre>
<h2>Compilando e Testando Workspaces</h2>
<h3>Compilação e Execução</h3>
<p>O Cargo entende automaticamente a estrutura do workspace. Para compilar tudo:</p>
<pre><code class="language-bash">cargo build</code></pre>
<p>Para compilar uma crate específica:</p>
<pre><code class="language-bash">cargo build -p cli
cargo build -p web_server</code></pre>
<p>Para executar um binário específico:</p>
<pre><code class="language-bash">cargo run -p cli</code></pre>
<h3>Testes em Larga Escala</h3>
<p>Teste todos os pacotes simultaneamente:</p>
<pre><code class="language-bash">cargo test</code></pre>
<p>Ou teste uma crate específica:</p>
<pre><code class="language-bash">cargo test -p core</code></pre>
<p>Com resultado detalhado:</p>
<pre><code class="language-bash">cargo test -- --test-threads=1 --nocapture</code></pre>
<p>Exemplo de teste em <code>core/src/lib.rs</code>:</p>
<pre><code class="language-rust">#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_user_creation() {
let user = User::new("Bob", 25);
assert_eq!(user.name, "Bob");
assert_eq!(user.age, 25);
}
}</code></pre>
<h2>Boas Práticas e Otimizações</h2>
<p>Um workspace bem organizado segue alguns princípios. Sempre mantenha dependências no escopo <code>[workspace.dependencies]</code> para evitar version skew. Use features condicionais para compilações mais eficientes — por exemplo, a crate <code>core</code> pode expor features que apenas <code>web_server</code> necessita. Documente a responsabilidade de cada crate em um <code>README.md</code> na raiz do workspace explicando qual module lidar com qual aspecto da aplicação.</p>
<p>Para projetos muito grandes, considere separar workspaces por domínio: um para infraestrutura, outro para features de negócio. Use <code>cargo workspaces</code> (ferramenta auxiliar) para gerenciar versionamento e publicação coordenada. Finalmente, configure <code>Cargo.toml</code> raiz com <code>default-members</code> caso nem todas as crates devam ser compiladas por padrão:</p>
<pre><code class="language-toml">[workspace]
members = ["core", "cli", "web_server", "internal_tools"]
default-members = ["core", "cli"]</code></pre>
<h2>Conclusão</h2>
<p>Workspaces no Cargo são essenciais para organizar projetos Rust complexos sem sacrificar performance. Os três aprendizados principais são: <strong>(1)</strong> compartilhar dependências e configuração via <code>[workspace.dependencies]</code> reduz tempo de compilação drasticamente, <strong>(2)</strong> dependências internas com <code>path</code> permitem desenvolvimento ágil sem publicar em crates.io, e <strong>(3)</strong> a estrutura unificada de <code>target/</code> economiza espaço enquanto mantém cada crate independente e testável. Domine esses conceitos e você terá uma base sólida para escalar projetos em Rust.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://doc.rust-lang.org/cargo/reference/workspaces.html" target="_blank" rel="noopener noreferrer">The Cargo Book - Workspaces</a></li>
<li><a href="https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html" target="_blank" rel="noopener noreferrer">Rust Book - Packages and Crates</a></li>
<li><a href="https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table" target="_blank" rel="noopener noreferrer">Cargo Workspace Dependencies</a></li>
<li><a href="https://www.rust-lang.org/what/wg-cargo/" target="_blank" rel="noopener noreferrer">Managing Large Projects in Rust</a></li>
<li><a href="https://tokio.rs/" target="_blank" rel="noopener noreferrer">Tokio Documentation - Using Workspaces</a></li>
</ul>