sccache em Rust: Cache de Compilação e CI | Rust Brasil

Aprenda a usar sccache em projetos Rust: RUSTC_WRAPPER, cache local e S3/GCS, GitHub Actions, Docker, mold e cargo-chef. Reduza rebuilds de crates na CI e no time.

O sccache é o jeito mais direto de parar de recompilar as mesmas crates Rust em todo cargo build da CI e do time: ele envolve o rustc via RUSTC_WRAPPER=sccache e reutiliza resultados idênticos entre máquinas, branches e pipelines. Instale com cargo install sccache --locked, exporte o wrapper e valide com sccache --show-stats. Em monorepos e em empresas que usam Rust com dezenas de serviços, o impacto costuma ser maior do que qualquer micro-otimização de código.

Este guia cobre o que é o sccache, como instalá-lo, como configurá-lo localmente e na CI, como usar backends remotos (S3/GCS/Redis), como combiná-lo com mold, cargo-chef e cargo-nextest, e como evitar os erros que zeraram o cache de muita equipe em 2026. Se o seu problema ainda é “não sei onde o build gasta tempo”, comece pelo guia de tempo de compilação e só depois invista em backend remoto.

Por que cache de compilação importa em Rust

Rust paga um preço alto na compilação por razões boas: monomorfização de genéricos, otimizações agressivas, verificação estática profunda e crates com muitas features. Em um serviço Axum + Tokio + Serde + SQLx, o grafo de dependências facilmente passa de centenas de crates.

Sem cache compartilhado, cada cenário repete o mesmo trabalho:

  1. notebook do dev A compila hyper e tokio do zero;
  2. notebook do dev B repete a mesma compilação no dia seguinte;
  3. CI no PR recompila quase tudo a cada push;
  4. job de release recompila de novo com flags levemente diferentes.

O Cargo já tem target/ incremental local. Isso ajuda você no mesmo checkout. Não ajuda o colega, não ajuda o runner efêmero da CI e não ajuda outro repositório que depende das mesmas versões. O sccache preenche exatamente esse buraco: cache de compilador entre contextos.

O que é sccache

sccache (Shared Compilation Cache) é um wrapper de compilador mantido pela comunidade (origem Mozilla) que intercepta invocações de rustc, gcc, clang e outros. Para Rust, o fluxo prático é:

  1. o Cargo decide o que compilar;
  2. em vez de chamar rustc direto, o ambiente aponta RUSTC_WRAPPER=sccache;
  3. o sccache calcula uma chave a partir das entradas relevantes (código, flags, toolchain, target, etc.);
  4. se a chave já existe no cache, devolve o artefato; senão, compila e grava o resultado.

Importante: sccache não substitui o Cargo, não baixa crates do crates.io e não resolve o link final do binário. Ele cacheia o trabalho caro do rustc sobre crates cujas entradas não mudaram.

sccache vs cache de target/ vs cargo-chef

CamadaO que reutilizaEscopo típicoLimite
target/ incremental do Cargoobjetos e metadados do checkoutmesma máquina / mesmo jobsome com runner limpo
sccacheresultados de compilação do rustcdevs + CI + projetossensível a flags e toolchain
cargo-cheflayer Docker de dependênciasbuilds containerizadosnão ajuda build nativo fora da imagem
mold / LLDnada de cache; acelera o linkLinux (mold) / multiplataforma (LLD)não evita recompilar crates

Regra prática: se o relatório de cargo build --timings mostra muito tempo em crates de dependência, sccache é candidato forte. Se o tempo está no link, vá para o mold. Se o Docker recompila deps a cada mudança de código, use cargo-chef.

Como instalar o sccache

Via Cargo (mais comum em dev)

cargo install sccache --locked
sccache --version

Binário de release

Em CI, muitas equipes preferem baixar o binário pré-compilado da página de releases do sccache para não gastar minutos compilando o próprio cacheador. Em imagens Docker de build, o binário estático ou o pacote da distro costuma ser mais previsível do que cargo install dentro do job.

Verificação mínima

export RUSTC_WRAPPER=sccache
cargo clean -p seu_crate_app   # opcional: force recompile de algo pequeno
cargo build
sccache --show-stats

Na primeira execução você verá sobretudo misses. Na segunda, com o mesmo código e as mesmas flags, os hits devem subir. Se os hits ficarem em zero, o problema quase nunca é “sccache não funciona” — é chave instável (veja a seção de troubleshooting).

Configuração local: o mínimo que funciona

Wrapper no shell

# ~/.bashrc ou ~/.zshrc
export RUSTC_WRAPPER=sccache
# opcional: tamanho do cache local (exemplos)
export SCCACHE_CACHE_SIZE="20G"

Wrapper só em um projeto

Evite poluir o ambiente global se o time ainda está experimentando:

# na sessão do projeto
export RUSTC_WRAPPER=sccache
cargo build
cargo test

Para desligar temporariamente (debug de bug estranho no rustc):

unset RUSTC_WRAPPER
# ou
export RUSTC_WRAPPER=

Onde o cache local mora

Por padrão o sccache grava em um diretório de cache do usuário (variável e SO-específico). Em notebooks com SSD pequeno, limite o tamanho com SCCACHE_CACHE_SIZE. Em monorepos grandes, 10–50 GB de cache local não é exagero se você alterna entre branches e workspaces.

Backends remotos: S3, GCS, Redis e empresa

Cache local acelera você. Backend remoto acelera o time e a CI.

Quando vale a pena

  • vários repositórios Rust com overlap de dependências;
  • frota de runners efêmeros (GitHub Actions, Gitea Actions, GitLab);
  • monorepo com dezenas de crates e PRs paralelos;
  • builds de múltiplos targets (x86_64-unknown-linux-gnu, aarch64, WASM, etc.) com overlap parcial.

Esboço com S3-compatível

export RUSTC_WRAPPER=sccache
export SCCACHE_BUCKET="empresa-sccache-rust"
export SCCACHE_REGION="sa-east-1"
# credenciais via IAM role, OIDC ou variáveis padrão AWS
export SCCACHE_S3_KEY_PREFIX="rust/"

Use prefixos por toolchain ou por repositório se quiser isolar políticas de retenção. Em ambientes corporativos brasileiros, buckets em sa-east-1 (São Paulo) reduzem latência de hit em relação a regiões distantes — meça; às vezes a CPU do compile ainda domina a rede.

GCS e Redis

GCS segue o mesmo espírito (bucket + credencial de service account). Redis aparece em setups que já têm Redis interno de baixa latência e querem cache quente entre jobs do mesmo cluster. A regra de ouro não muda: o backend só ajuda se as chaves forem estáveis.

Segurança

Cache de compilação pode conter artefatos derivados de código proprietário. Trate o bucket como dado interno:

  • acesso autenticado (nada de bucket público);
  • criptografia em repouso;
  • política de lifecycle (apagar objetos antigos);
  • segregação por ambiente se compliance exigir.

Não coloque secrets de produção dentro do cache de build; secrets pertencem a um gerenciador de segredos, não a objetos de compilação.

sccache na CI (GitHub Actions / Gitea Actions)

O padrão que funciona na maioria dos pipelines Rust:

  1. instalar sccache (binário);
  2. exportar RUSTC_WRAPPER=sccache;
  3. restaurar cache local ou apontar backend remoto;
  4. rodar cargo build / cargo nextest;
  5. gravar estatísticas no log (sccache --show-stats);
  6. persistir o cache local se não houver backend remoto.

Exemplo conceitual (local cache + actions/cache)

env:
  RUSTC_WRAPPER: sccache
  SCCACHE_CACHE_SIZE: "5G"

steps:
  - uses: actions/checkout@v4
  - name: Install sccache
    run: |
      # baixe o binário da release ou use cargo install --locked
      sccache --version
  - name: Cache sccache
    uses: actions/cache@v4
    with:
      path: ~/.cache/sccache
      key: sccache-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
      restore-keys: |
        sccache-${{ runner.os }}-
  - name: Build
    run: cargo build --workspace --all-targets
  - name: Stats
    run: sccache --show-stats

Ajuste o path do cache ao diretório real do sccache no runner. O key com Cargo.lock é um bom ponto de partida; chaves demais (que mudam a cada commit) destroem a taxa de hit.

CI com backend S3

Se vários workflows e repositórios compartilham o mesmo bucket, o actions/cache local vira complementar, não principal. OIDC para assumir role na AWS evita access keys de longa duração nos secrets do repositório — padrão recomendado em 2026.

O que logar sempre

  • rustc --version / rustup show;
  • sccache --version;
  • sccache --show-stats no final;
  • tempo total do job (para correlacionar hit rate com minutos economizados).

Sem essas linhas, ninguém prova que o cache está ajudando — e cache “mágico” sem métrica morre no próximo corte de custo.

Docker: sccache + multi-stage + cargo-chef

Docker e sccache se complementam, não se substituem.

Papel de cada um

  • cargo-chef: evita recompilar dependências quando só o seu código mudou, graças a layers estáveis;
  • sccache: reutiliza compilação de crates entre builds diferentes, imagens diferentes e até repos diferentes, se o backend for compartilhado;
  • mold: encurta o link dentro do builder Linux.

Padrão saudável

  1. stage chef / planner com cargo-chef (como no guia dedicado);
  2. stage builder com toolchain Rust, mold e sccache;
  3. ENV RUSTC_WRAPPER=sccache no builder;
  4. backend remoto ou volume de cache montado no builder;
  5. stage final mínimo só com o binário (sem sccache, sem toolchain).

Evite copiar o cache do sccache para a imagem final de produção. Cache é ferramenta de build, não runtime.

Para o desenho completo de imagens enxutas, veja também Rust e Docker: builds otimizados para produção.

Combinando sccache com o resto do kit 2026

Times maduros de Rust não escolhem uma ferramenta de build — montam um sistema:

SintomaFerramentaGuia
Crates recompilam em todo job/CIsccache (este guia)
Link lento no Linuxmoldmold linker
Docker recompila deps a cada commitcargo-chefcargo-chef
Suíte de testes lentacargo-nextestnextest
Não sei onde o tempo vaicargo build --timingstempo de compilação
Pipeline completocache + test + deployCI/CD Rust
CPU em produção, não no buildprofilingprofiling

Ordem de adoção recomendada para um time que ainda não tem nada disso:

  1. medir com --timings;
  2. sccache local no dev + cache na CI;
  3. mold no Linux;
  4. cargo-chef no Docker;
  5. nextest na suíte;
  6. backend remoto de sccache quando o hit rate local provar valor.

Estabilidade da chave: o que mata o hit rate

A maior parte das decepções com sccache vem de chaves instáveis. Cada diferença abaixo pode transformar um hit em miss:

Toolchain diferente

rustc 1.8x.0 e 1.8x.1 não compartilham artefatos. Pine a toolchain com rust-toolchain.toml no repositório e use a mesma no CI.

RUSTFLAGS e profiles

Flags de link, cfg, -C target-cpu, sanitizers e profiles customizados entram na identidade da compilação. Um job de CI com RUSTFLAGS="-C debuginfo=0" e outro sem isso fragmenta o cache.

Features de workspace

Compilar cargo build -p api --features otel e cargo build -p api sem features gera artefatos diferentes para a mesma crate raiz e, em cascata, para dependências condicionais. Padronize features de CI.

Targets cruzados

x86_64-unknown-linux-gnu e aarch64-unknown-linux-gnu são caches distintos — e devem ser. Não espere que build amd64 aqueça o cache de arm64.

Paths absolutos e reproducibilidade

Alguns cenários sensíveis a path ainda aparecem em crates com build scripts antigos. Prefira builds determinísticos, Cargo.lock commitado e evite injetar timestamps em build.rs sem necessidade.

Troubleshooting rápido

sccache --show-stats sempre em zero hits

  1. confirme echo $RUSTC_WRAPPER → deve ser sccache;
  2. rode o mesmo cargo build duas vezes sem cargo clean;
  3. verifique se algum script faz unset RUSTC_WRAPPER;
  4. confira se a CI restaura o diretório/backend certo;
  5. veja se a toolchain muda entre runs.

Build fica mais lento com sccache

Pode acontecer no primeiro aquecimento ou com backend remoto de alta latência e hit rate baixo. Meça cold vs warm. Se o warm não ganhar, o gargalo não é recompilação de crates — olhe link e testes.

Erros estranhos só com o wrapper

Isole:

unset RUSTC_WRAPPER
cargo build

Se passar sem sccache, atualize o sccache, limpe o cache corrompido e abra issue com versões de rustc e sccache. Em paralelo, pin a versão do sccache na CI para não surfar breaking change no meio do sprint.

Cache estoura disco

Reduza SCCACHE_CACHE_SIZE, configure lifecycle no bucket ou separe prefixos por projeto. Cache sem política de retenção vira custo silencioso.

sccache e carreira: o que entrevistadores querem ouvir

Em vagas de backend sênior, plataforma e DevOps com Rust no Brasil, “como você reduz o tempo de feedback do monorepo?” virou pergunta clássica. Uma resposta forte não é “a gente usa sccache” — é:

  1. medimos com cargo build --timings e métricas de CI;
  2. separamos gargalos de compile, link e teste;
  3. aplicamos sccache / mold / chef / nextest onde cada um paga;
  4. acompanhamos hit rate e minutos de runner;
  5. documentamos toolchain e flags para o cache não apodrecer.

Isso demonstra engenharia de entrega, não só sintaxe de ownership. Para mapear o mercado, acompanhe vagas Rust, salários e o panorama de carreira em Rust.

Checklist de adoção

  • sccache --version no PATH de dev e CI;
  • RUSTC_WRAPPER=sccache documentado no README do time;
  • rust-toolchain.toml pinando a versão do compilador;
  • segundo cargo build local mostra hits em --show-stats;
  • CI imprime stats no fim do job;
  • cache local persistido ou backend remoto configurado;
  • RUSTFLAGS/features padronizados entre jobs comparáveis;
  • mold habilitado no Linux se o link for gargalo;
  • Docker multi-stage não leva sccache para a imagem final;
  • política de retenção do cache (disco ou bucket) definida.

Conclusão

O sccache é a peça de cache de compilação que falta em muitos times Rust que já otimizaram código e ainda sangram minutos de CI. Ele não é mágica: exige toolchain estável, flags coerentes e métricas. Mas, quando a chave está correta, transforma o custo de recompilar tokio, hyper, serde e centenas de crates transitivas em hits baratos — no notebook, no PR e no release.

Monte o sistema completo: meça com timings, cacheie compile com sccache, acelere link com mold, estabilize Docker com cargo-chef e paralelize testes com nextest. Esse combo é o padrão de engenharia que aparece em times sérios de Rust em 2026 — e é o tipo de prática que o mercado brasileiro passa a cobrar quando a linguagem sai do piloto e entra no núcleo do produto.

Perguntas frequentes

O que é sccache?

sccache é um cache compartilhado de compilador. Em Rust, ele atua como RUSTC_WRAPPER, reutilizando resultados do rustc quando as entradas da compilação são as mesmas entre máquinas, branches e pipelines.

Como ativar sccache no Cargo?

cargo install sccache --locked
export RUSTC_WRAPPER=sccache
cargo build
sccache --show-stats

Na CI, instale o binário, exporte o wrapper e persista o cache local ou use backend remoto.

sccache substitui mold e cargo-chef?

Não. sccache cacheia compilação; mold acelera o link; cargo-chef estabiliza dependências em layers Docker. Combine conforme o gargalo medido.

sccache funciona com workspaces?

Sim. Workspaces com dependências compartilhadas são exatamente o cenário em que o hit rate costuma ser alto — desde que toolchain e features sejam estáveis.

sccache ou ccache?

Para Rust, prefira sccache. ccache é o clássico de C/C++; sccache entende o fluxo do rustc e é o padrão do ecossistema Rust em CI moderna.

Quando sccache não ajuda?

Quando o tempo está no link ou nos testes, quando cada job usa flags diferentes, ou quando a toolchain muda o tempo todo. Meça antes de escalar para S3.

Leia também