Reprodutibilidade e isolamento de ambientes no R
Esta aula foi construída para que você entenda como proteger seus projetos de quebras causadas por atualizações de pacotes e incompatibilidades de ambiente. Todo o código está funcional e pronto para reproduzir.
Inscreva-se já no canal Link.
renv resolverenvrenv com Git e GitHubVocê termina uma análise, compartilha o script com um colega e ele retorna com um erro que você nunca viu.
Ou você volta a um projeto de seis meses atrás, roda o código e tudo quebra, porque algum pacote foi atualizado e a função mudou de nome, de argumento ou de comportamento.
Ou você sobe o projeto no GitHub e o GitHub Actions falha porque a versão do pacote no servidor é diferente da sua máquina.
Esses três cenários têm a mesma causa: o ambiente R não está registrado junto com o código.
Ambiente R é o conjunto de pacotes e versões instalados na sua máquina que o R usa quando executa um script.
Dois computadores com R instalado podem ter ambientes completamente diferentes:
Quando um script depende implicitamente de um ambiente específico e esse ambiente não está documentado, o script deixa de ser reproduzível.
Reprodutibilidade é a capacidade de um script produzir exatamente o mesmo resultado quando executado em condições idênticas, inclusive por outra pessoa em outro computador.
Para que um projeto seja reproduzível, três coisas precisam estar registradas:
renv)O renv é responsável pela terceira parte.
renv.lock.packrat, que era a solução anterior para o mesmo problemaBiblioteca global é a pasta onde o R instala pacotes por padrão. Todos os projetos do seu computador compartilham a mesma biblioteca global.
Biblioteca isolada é uma pasta criada pelo renv dentro do projeto. Cada projeto tem a sua. Pacotes instalados em um projeto não afetam outros projetos.
Important
Por que isso importa: se você atualiza o ggplot2 na biblioteca global para usar em um novo projeto, todos os seus projetos anteriores que dependem de uma versão específica do ggplot2 podem parar de funcionar. Com o renv, cada projeto usa sua própria versão registrada.
renv que registra:O renv.lock deve ser versionado no Git.
Ele é o equivalente ao requirements.txt do Python ou ao package.json do Node.js.
Quando outra pessoa clona o repositório e roda
renv::restore(), orenvlê orenv.locke instala exatamente os mesmos pacotes e versões que você usou.
Tip
Regra: versione o renv.lock, nunca versione a pasta renv/library/.
renv::restore() e não precisa estar no repositório.O renv só precisa ser instalado uma vez na biblioteca global.
A partir daí, ele gerencia as bibliotecas isoladas de cada projeto.
Conceito: renv::init() ativa o renv em um projeto existente ou novo.
Ele realiza quatro ações em sequência:
renv/ dentro do projetorenv/library/renv.lock com os pacotes detectados* Initializing project ...
* Discovering package dependencies ... Done!
* Copying packages into the cache ... Done!
The following package(s) will be updated in the lockfile:
# CRAN --------------------------------------------------------------
- dplyr [* -> 1.1.4]
- ggplot2 [* -> 3.5.0]
- tidyr [* -> 1.3.1]
- readr [* -> 2.1.5]
* Lockfile written to '~/meu_projeto/renv.lock'.
O asterisco [*] indica que o pacote não estava no lockfile antes.
A seta -> mostra a versão que foi registrada.
renv::init(), o projeto terá essa estrutura adicional:meu_projeto/
├── renv/
│ ├── activate.R # script de ativação automática
│ ├── library/ # biblioteca isolada (não versionar)
│ └── settings.json # configurações do renv
├── renv.lock # arquivo de bloqueio (versionar)
└── .Rprofile # ativa o renv automaticamente ao abrir o projeto
.Rprofile contém uma linha que carrega o renv toda vez que o projeto é aberto no RStudio:renv::status() compara três fontes de informação:library() e require())renv.lockQuando as três fontes estão sincronizadas, o projeto está em estado consistente.
* The project is already synchronized with the lockfile.
Esse é o estado desejado.
Significa que o que está no código, na biblioteca e no lockfile é idêntico.
The following package(s) are installed but not recorded in the lockfile:
_
lubridate [1.9.3]
The following package(s) are used in the project but are not installed:
_
patchwork [*]
Use `renv::snapshot()` to save the state of your project.
Use `renv::restore()` to install the packages recorded in the lockfile.
O renv identifica três situações distintas:
pacote instalado mas não registrado;
pacote registrado mas não instalado;
e pacote usado no código mas não instalado.
Conceito: renv::snapshot() atualiza o renv.lock com o estado atual da biblioteca isolada.
Deve ser executado sempre que você instalar, atualizar ou remover um pacote.
O snapshot() detecta automaticamente quais pacotes são usados no projeto percorrendo todos os arquivos .R, .Rmd e .qmd em busca de chamadas library() e require().
The following package(s) will be updated in the lockfile:
# CRAN -----------------------------------------------------------------------
- lubridate [* -> 1.9.3]
- patchwork [* -> 1.2.0]
Do you want to proceed? [Y/n]: Y
* Lockfile written to '~/meu_projeto/renv.lock'.
O renv pede confirmação antes de sobrescrever o lockfile.
Isso evita atualizações acidentais.
renv oferece diferentes estratégias de snapshot controladas por renv::settings$snapshot.type():| Tipo | Comportamento |
|---|---|
"implicit" (padrão) |
Registra apenas pacotes usados no código |
"explicit" |
Registra apenas pacotes listados no DESCRIPTION |
"all" |
Registra todos os pacotes instalados na biblioteca |
"implicit" é o mais indicado para projetos de análise porque mantém o lockfile enxuto.Conceito: renv::restore() lê o renv.lock e instala exatamente as versões registradas.
É o comando que outra pessoa executa ao clonar seu repositório.
O restore() não altera pacotes que já estão instalados com a versão correta.
Ele instala apenas o que está ausente ou em versão diferente.
The following package(s) will be updated:
# CRAN -----------------------------------------------------------------------
- dplyr [1.1.2 -> 1.1.4]
- ggplot2 [3.4.4 -> 3.5.0]
Do you want to proceed? [Y/n]: Y
* Restoring library ... Done!
* The project has been restored.
restore() mostra a versão atual e a versão do lockfile para cada pacote que será alterado.Quatro situações em que renv::restore() é o primeiro comando a executar:
renv.lock e precisa instalar os pacotesrenv::status() indicou que há pacotes ausentesConceito: renv::install() instala um pacote diretamente na biblioteca isolada do projeto.
É preferível a install.packages() dentro de um projeto com renv ativo porque já atualiza o cache interno do renv.
Retrieving 'https://cloud.r-project.org/src/contrib/janitor_2.2.0.tar.gz' ...
OK [downloaded 293.5 Kb in 1.2s]
Installing janitor [2.2.0] ...
OK [built from source in 8.3s]
* Run `renv::snapshot()` to update the project lockfile.
renv lembra de executar renv::snapshot() para registrar o novo pacote no lockfile.renv::update() atualiza pacotes para versões mais recentes dentro da biblioteca isolada. A atualização não é automática - você decide quando e quais pacotes atualizar.The following package(s) will be updated:
# CRAN -----------------------------------------------------------------------
- ggplot2 [3.4.4 -> 3.5.1]
Do you want to proceed? [Y/n]: Y
* Updating packages ...
OK [installed ggplot2 3.5.1 in 12.4s]
* Run `renv::snapshot()` to save these changes to the lockfile.
Após atualizar, execute renv::snapshot() para registrar a nova versão no lockfile. Se a atualização causar problemas, use renv::restore() para voltar ao estado anterior.
Conceito: renv::remove() remove um pacote da biblioteca isolada e do lockfile. Útil quando um pacote deixou de ser utilizado no projeto e você quer manter o ambiente enxuto.
The following packages will be removed:
janitor
Do you want to proceed? [Y/n]: Y
* Removing package 'janitor' ... Done!
* Run `renv::snapshot()` to update the project lockfile.
Note
Importante: renv::remove() remove o pacote da biblioteca isolada do projeto, não da biblioteca global nem do cache interno do renv.
O pacote continua disponível para outros projetos.
Conceito: nem tudo que o renv cria deve ser versionado no Git.
O renv gera automaticamente um .gitignore dentro da pasta renv/ com as exclusões corretas.
# Conteúdo de renv/.gitignore gerado automaticamente
library/
local/
lock/
python/
staging/
| Arquivo ou pasta | Versionar? | Motivo |
|---|---|---|
renv.lock |
Sim | Registro das versões - deve ser compartilhado |
.Rprofile |
Sim | Ativa o renv ao abrir o projeto |
renv/activate.R |
Sim | Script de ativação |
renv/settings.json |
Sim | Configurações do projeto |
renv/library/ |
Não | Gerada localmente pelo restore() |
renv/staging/ |
Não | Temporária, gerada durante operações |
# renv
renv/library/
renv/local/
renv/staging/
# R
.Rhistory
.RData
.Ruserdata
.Rproj.user
A pasta renv/library/ pode conter centenas de megabytes.
Versioná-la tornaria o repositório inutilizável e não teria nenhum benefício, já que qualquer pessoa pode regenerá-la com renv::restore().
renv em equipe segue uma sequência bem definida que garante que todos os colaboradores trabalhem com o mesmo ambiente.# --- Colaborador A (quem criou o projeto) ---
# 1. Inicializa o renv
renv::init()
# 2. Instala os pacotes necessários
renv::install(c("tidyverse", "janitor", "gtsummary"))
# 3. Registra no lockfile
renv::snapshot()
# 4. Versiona e compartilha
# git add renv.lock .Rprofile renv/activate.R
# git commit -m "feat: inicializa renv com pacotes do projeto"
# git push# --- Colaborador B (quem clonou o projeto) ---
# 1. Clona o repositório
# git clone https://github.com/usuario/projeto.git
# 2. Abre o projeto no RStudio
# O .Rprofile ativa o renv automaticamente
# 3. Restaura o ambiente
renv::restore()
# Instala exatamente os mesmos pacotes e versões do lockfile
# 4. Trabalha normalmente
# library(tidyverse)
# source("R/01_analise.R")# Colaborador A atualiza um pacote e registra
renv::update("ggplot2")
renv::snapshot()
# git add renv.lock
# git commit -m "chore: atualiza ggplot2 para 3.5.1"
# git push
# ---
# Colaborador B puxa as mudanças e restaura o ambiente
# git pull
renv::restore()
# Instala ggplot2 3.5.1 para ficar igual ao lockfile atualizadorenv mantém um cache global de pacotes no seu computador, separado das bibliotecas isoladas de cada projeto.Quando você instala um pacote em um projeto, o renv:
[1] "/Users/jennifer/Library/Caches/org.R-project.R/R/renv/cache/v5/R-4.4/x86_64-apple-darwin20"
O cache é organizado por versão do R e arquitetura do sistema.
Isso garante compatibilidade entre diferentes versões do R instaladas no mesmo computador.
renv::status() antes de fazer commit para garantir que o lockfile está sincronizado com o códigorenv::snapshot() imediatamente após instalar ou remover pacotes, não acumule mudanças antes de registrarrenv.lock em todo commit que modifica dependências com uma mensagem descritiva: chore: atualiza janitor para 2.2.0renv.lock manualmente. O arquivo é gerado pelo renv e editá-lo manualmente pode corromper as referências de hashrenv::install() em vez de install.packages() dentro de projetos com renv ativo| Situação | Causa | Solução |
|---|---|---|
renv::status() mostra pacotes fora de sincronia |
Pacote instalado sem renv::snapshot() |
Executar renv::snapshot() |
renv::restore() falha com erro de compilação |
Dependências do sistema ausentes | Instalar libs do sistema (ex: libcurl, openssl) |
Pacote instalado não é detectado pelo status() |
Pacote não está sendo chamado com library() no código |
Adicionar library() ou usar tipo "all" no snapshot |
| Situação | Causa | Solução |
|---|---|---|
Projeto abre sem ativar o renv |
.Rprofile ausente ou não versionado |
Verificar se .Rprofile está no repositório |
renv::restore() instala versão errada |
renv.lock desatualizado no repositório |
Fazer git pull e executar renv::restore() novamente |
| Cache corrompido após falha de instalação | Download interrompido ou disco cheio | Executar renv::rebuild() para reinstalar do zero |
| Função | Quando usar |
|---|---|
renv::init() |
Uma vez, ao iniciar o projeto com renv |
renv::status() |
Antes de commits e para diagnosticar problemas |
renv::snapshot() |
Após instalar, atualizar ou remover pacotes |
renv::restore() |
Ao clonar o projeto ou após git pull com mudanças no lockfile |
renv::install() |
Para instalar pacotes dentro do projeto |
renv::update() |
Para atualizar pacotes com controle |
renv::remove() |
Para remover pacotes que não são mais usados |
renv::paths$cache() |
Para verificar a localização do cache global |
renv::rebuild() |
Para recompilar pacotes com problemas |
| Passo | Função | O que faz |
|---|---|---|
| 1 | renv::init() |
Inicializa o renv e cria a biblioteca isolada |
| 2 | renv::status() |
Diagnóstico de sincronização do ambiente |
| 3 | renv::snapshot() |
Registra os pacotes no renv.lock |
| 4 | renv::restore() |
Restaura o ambiente a partir do lockfile |
| 5 | renv::install() |
Instala pacotes na biblioteca isolada |
| 6 | renv::update() |
Atualiza pacotes com controle de versão |
| 7 | renv::remove() |
Remove pacotes do ambiente e do lockfile |
| 8 | .gitignore |
Define o que versionar e o que ignorar |
| 9 | Fluxo colaborativo | Como trabalhar em equipe com renv |
Reprodutibilidade é um requisito em ciência de dados aplicada, pesquisa acadêmica e ambientes corporativos.
Um projeto sem controle de ambiente pode produzir resultados diferentes dependendo de quando e onde é executado, o que compromete a confiabilidade das análises.
O renv é o padrão adotado pela comunidade R para esse controle.
Ele é equivalente ao requirements.txt do Python e ao Gemfile do Ruby, ferramentas que qualquer desenvolvedor experiente nessas linguagens usa por padrão.
Projetos com renv.lock versionado comunicam cuidado técnico e maturidade analítica para quem avalia o código.
Continue praticando e explorando!
Esta aula é parte do projeto Café com R. É open source. Use, compartilhe e adapte.
Que cada gole desperte uma nova ideia. Que cada script abra uma nova conversa. Que o Café com R se torne um ponto de encontro nosso.

Jennifer Lopes | Café com R