Golang

Go Modules: go.mod, go.sum e gerenciamento de dependências Já leu

9 min de leitura

Go Modules: go.mod, go.sum e gerenciamento de dependências
Antes dos módulos, Go usava o GOPATH — um diretório global onde todos os projetos e dependências conviviam. Não havia versionam

Antes dos módulos, Go usava o GOPATH — um diretório global onde todos os projetos e dependências conviviam. Não havia versionamento de dependências, não havia isolamento entre projetos e atualizar uma biblioteca podia quebrar todos os projetos simultaneamente. Era um sistema funcional para projetos pequenos e experimentos, mas inadequado para desenvolvimento profissional em escala.

Go Modules, introduzido como experimental no Go 1.11 e tornado padrão no Go 1.16, resolveu todos esses problemas. Cada projeto tem seu próprio conjunto de dependências versionadas, isolado dos demais. Builds são reproduzíveis — o mesmo código produz o mesmo binário em qualquer máquina. Atualizações são explícitas e controladas.


O arquivo go.mod

O go.mod é o manifesto do módulo. Ele declara o nome do módulo, a versão mínima do Go necessária e todas as dependências diretas:

module github.com/ricardomattos/loja-api

go 1.22

require (
    github.com/gin-gonic/gin v1.9.1
    github.com/golang-jwt/jwt/v5 v5.2.0
    gorm.io/gorm v1.25.7
    gorm.io/driver/postgres v1.5.6
)

require (
    // dependências indiretas — usadas por dependências diretas
    github.com/bytedance/sonic v1.11.3 // indirect
    github.com/gabriel-vasile/mimetype v1.4.3 // indirect
    golang.org/x/net v0.22.0 // indirect
)

O caminho do módulo — github.com/ricardomattos/loja-api — é o identificador único do módulo. Por convenção, projetos publicados usam o caminho do repositório onde o código reside. Para projetos privados ou locais, qualquer nome descritivo funciona.


O arquivo go.sum

O go.sum é o guardião da integridade das dependências. Para cada módulo listado no go.mod, o go.sum armazena o hash criptográfico do conteúdo esperado:

github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=

Quando você ou um colega executa go build ou go test, o Go verifica se os módulos baixados correspondem aos hashes registrados. Se alguém alterar o conteúdo de uma dependência publicada — seja maliciosamente ou por acidente — a verificação falha e o build é recusado.

Nunca edite o go.sum manualmente. Ele é gerenciado automaticamente pelos comandos go. Sempre faça commit de ambos go.mod e go.sum no controle de versão.


Comandos essenciais

Inicializando um módulo:

mkdir loja-api
cd loja-api
go mod init github.com/ricardomattos/loja-api

Adicionando uma dependência:

A forma mais direta é simplesmente importar o pacote no código e executar go mod tidy. Ou adicionar explicitamente com go get:

go get github.com/gin-gonic/gin@v1.9.1
go get gorm.io/gorm@latest

O sufixo @versão aceita: - @v1.9.1 — versão exata - @latest — versão mais recente estável - @main — branch específica (evite em produção) - @v1.9 — prefixo de versão

Removendo dependências não utilizadas e adicionando as faltantes:

go mod tidy

Este é o comando mais usado no dia a dia. Ele analisa todo o código do módulo, remove do go.mod dependências que não são mais importadas, adiciona as que estão sendo importadas mas não declaradas e atualiza o go.sum. Execute go mod tidy antes de todo commit.

Atualizando dependências:

# Atualizar uma dependência específica para a versão mais recente
go get github.com/gin-gonic/gin@latest

# Atualizar todas as dependências diretas para versões patch mais recentes
go get -u=patch ./...

# Atualizar todas as dependências diretas para versões minor mais recentes
go get -u ./...

Verificando dependências:

# Lista todas as dependências e suas versões
go list -m all

# Mostra por que uma dependência está no go.mod
go mod why github.com/gin-gonic/gin

# Verifica se o go.sum está correto
go mod verify

Versionamento semântico

Go Modules adota versionamento semântico — semver — com três componentes: MAJOR.MINOR.PATCH.

  • PATCH — correções de bugs sem quebrar compatibilidade: v1.2.3 → v1.2.4
  • MINOR — novas funcionalidades sem quebrar compatibilidade: v1.2.3 → v1.3.0
  • MAJOR — mudanças incompatíveis com versões anteriores: v1.2.3 → v2.0.0

Go trata versões MAJOR diferentes como módulos completamente distintos. Um módulo na versão v2 ou superior deve ter /v2 no final do caminho do módulo:

github.com/autor/biblioteca       ← v0 e v1
github.com/autor/biblioteca/v2    ← v2
github.com/autor/biblioteca/v3    ← v3

Isso permite que um projeto importe v1 e v2 de uma mesma biblioteca simultaneamente sem conflito — cada versão major é tratada como um módulo independente.


Algoritmo de versão mínima (MVS)

O Go usa o Minimum Version Selection para resolver versões de dependências, em vez de "pegar a mais recente". Dado que o projeto A requer B@v1.2 e C@v1.0, e que C@v1.0 requer B@v1.3, o Go seleciona B@v1.3 — a versão mínima que satisfaz todos os requisitos.

Esse algoritmo tem uma propriedade valiosa: ele é determinístico e conservador. Atualizar uma dependência direta nunca atualiza automaticamente outras dependências além do necessário. Isso torna os builds previsíveis e as atualizações controláveis.


Replace e exclude

O go.mod suporta diretivas avançadas para situações especiais.

replace — substitui um módulo por outro, útil para desenvolvimento local ou para usar um fork:

replace (
    // Usar versão local durante desenvolvimento
    github.com/ricardomattos/pacote-compartilhado => ../pacote-compartilhado

    // Usar um fork em vez do original
    github.com/original/biblioteca => github.com/meufork/biblioteca v1.0.0-fork
)

Remova todas as diretivas replace de desenvolvimento antes de publicar o módulo — elas não funcionam para quem baixar sua biblioteca.

exclude — exclui uma versão específica de uma dependência, geralmente por conter um bug crítico:

exclude github.com/alguma/biblioteca v1.5.2

Workspaces: múltiplos módulos locais

Go 1.18 introduziu workspaces (go work) para facilitar o desenvolvimento simultâneo de múltiplos módulos relacionados sem precisar usar replace:

# Na raiz que contém os dois módulos
go work init ./loja-api ./pacote-compartilhado

Isso cria um arquivo go.work:

go 1.22

use (
    ./loja-api
    ./pacote-compartilhado
)

Com o workspace ativo, mudanças em pacote-compartilhado são imediatamente visíveis em loja-api sem necessidade de publicar ou usar replace. O go.work não deve ser commitado — adicione-o ao .gitignore.


Cache de módulos

Go mantém um cache local de todos os módulos baixados em $GOPATH/pkg/mod. Uma vez baixado, um módulo não é baixado novamente — mesmo em projetos diferentes que usam a mesma versão.

# Ver o diretório do cache
go env GOMODCACHE

# Limpar o cache completamente
go clean -modcache

O cache é somente-leitura após o download, o que evita modificações acidentais. Se precisar editar uma dependência, faça um fork e use replace.


Proxy de módulos

Por padrão, Go baixa módulos através do proxy oficial proxy.golang.org, que serve como cache e espelho de módulos públicos. Isso garante disponibilidade mesmo se o repositório original for removido.

A variável GOPROXY controla quais proxies são usados:

# Padrão — proxy oficial com fallback direto
GOPROXY=https://proxy.golang.org,direct

# Sem proxy — acesso direto aos repositórios
GOPROXY=direct

# Proxy corporativo para ambientes fechados
GOPROXY=https://proxy.minha-empresa.com,direct

A variável GONOSUMCHECK e GONOSUMDB controlam quais módulos ignoram a verificação de integridade — útil para módulos privados que não estão registrados na sumdb pública.


Exemplo completo: projeto real com dependências

mkdir api-tarefas
cd api-tarefas
go mod init github.com/ricardomattos/api-tarefas
// main.go
package main

import (
    "github.com/ricardomattos/api-tarefas/internal/handler"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/tarefas", handler.ListarTarefas)
    r.POST("/tarefas", handler.CriarTarefa)
    r.Run(":8080")
}
# Adicionar dependências detectadas no código
go mod tidy

Após go mod tidy, o go.mod será atualizado automaticamente com Gin e todas as suas dependências transitivas. O go.sum será gerado com os hashes correspondentes.

# Verificar o resultado
cat go.mod

# Confirmar que tudo está correto
go build ./...
go test ./...

Resumo do que foi coberto

Este artigo apresentou Go Modules em profundidade: a estrutura e propósito dos arquivos go.mod e go.sum, os comandos essenciais do dia a dia, versionamento semântico com versões MAJOR como módulos distintos, o algoritmo MVS, as diretivas replace e exclude, workspaces para desenvolvimento multi-módulo, o cache local e o sistema de proxies. Com módulos dominados, o próximo artigo explora a biblioteca padrão do Go.


Referências e leituras complementares

  • Documentação oficial de Go Modules — Referência completa e autoritativa sobre o sistema de módulos. https://go.dev/ref/mod

  • Go Blog: Using Go Modules — Série de artigos introdutórios sobre módulos. https://go.dev/blog/using-go-modules

  • Go Blog: Go Modules in 2019 — Contexto histórico e motivações do sistema de módulos. https://go.dev/blog/modules2019

  • pkg.go.dev — Repositório central de documentação de módulos Go públicos. https://pkg.go.dev

  • Documentação de go work — Referência sobre workspaces para múltiplos módulos. https://go.dev/ref/mod#workspaces

  • Go Proxy Protocol — Especificação do protocolo de proxy de módulos. https://go.dev/ref/mod#goproxy-protocol

Comentários

Mais em Golang

Operadores, expressões e conversão de tipo
Operadores, expressões e conversão de tipo

Se variáveis são os substantivos de um programa, operadores s&a...

Ponteiros: conceito, uso e quando evitar
Ponteiros: conceito, uso e quando evitar

Ponteiros são um dos tópicos que mais intimidam iniciantes vind...

Maps: criação, iteração e boas práticas
Maps: criação, iteração e boas práticas

Se slices são a espinha dorsal das sequências em Go, maps s&atil...