---
title: "Go Workspaces com go.work: Guia para Múltiplos Módulos"
url: "https://golang.com.br/blog/go-work-go-workspaces-monorepo-multiplos-modulos/"
markdown_url: "https://golang.com.br/blog/go-work-go-workspaces-monorepo-multiplos-modulos.MD"
description: "Aprenda a usar go work e go.work para desenvolver vários módulos Go juntos, organizar monorepos, testar mudanças locais e evitar replaces frágeis."
date: "2026-08-22"
author: "Golang Brasil"
---

# Go Workspaces com go.work: Guia para Múltiplos Módulos

Aprenda a usar go work e go.work para desenvolver vários módulos Go juntos, organizar monorepos, testar mudanças locais e evitar replaces frágeis.


**Resposta rápida:** use **Go Workspaces** quando você precisa alterar e testar **dois ou mais módulos Go ao mesmo tempo**. Na raiz do trabalho, rode `go work init`, adicione os módulos com `go work use` e execute os comandos normalmente. O arquivo `go.work` faz o toolchain resolver os imports pelo código local, sem publicar versões provisórias e sem espalhar `replace ../outro-modulo` pelos arquivos `go.mod`. Ele é especialmente útil em monorepos, na evolução conjunta de uma biblioteca e uma API e na reprodução local de mudanças que atravessam repositórios.

O recurso não transforma vários módulos em um único projeto. Cada diretório continua com seu próprio `go.mod`, suas dependências e seu ciclo de versão. O workspace é uma camada de desenvolvimento por cima desses módulos.

## Quando usar go.work

Um workspace resolve um problema específico: o módulo `app` depende de `lib`, você está mudando os dois, mas a nova versão de `lib` ainda não existe em um proxy de módulos.

Sem workspace, as alternativas comuns são:

1. publicar uma versão provisória da biblioteca;
2. editar o `go.mod` da aplicação com um `replace` para um caminho local;
3. copiar código entre projetos;
4. esperar a mudança da biblioteca ser publicada antes de testar a aplicação.

Com `go.work`, o código local entra na resolução sem modificar o `go.mod` que será consumido por outras pessoas.

| Situação | Go Workspace ajuda? | Motivo |
|---|---:|---|
| Monorepo com várias APIs e bibliotecas | Sim | Permite desenvolver e testar módulos juntos |
| Biblioteca e aplicação em clones vizinhos | Sim | Liga os módulos locais sem publicar uma versão |
| Projeto com um único módulo | Geralmente não | Um `go.mod` já resolve o caso |
| Dependência externa sem mudanças locais | Não | Use a versão normal declarada no `go.mod` |
| Fork permanente de uma dependência | Talvez | Um `replace` versionado pode expressar melhor a decisão |
| Pacotes internos de uma única aplicação | Não necessariamente | Antes de criar módulos, considere manter apenas pacotes |

A última linha é importante. **Nem todo diretório merece um módulo.** Criar muitos `go.mod` aumenta o trabalho de versionamento, atualização e CI. Use múltiplos módulos quando existem fronteiras reais: publicação independente, consumidores diferentes, restrições de dependência ou ciclos de release separados.

Se você ainda está consolidando esses conceitos, comece pelo guia de [Go Modules na prática](/aprenda/go-modules-na-pratica/) e pela referência de [módulos e dependências em Go](/aprenda/go-modules/).

## Exemplo: uma API e uma biblioteca local

Imagine esta estrutura:

```text
plataforma/
├── api/
│   ├── go.mod
│   └── main.go
└── saudacao/
    ├── go.mod
    └── saudacao.go
```

A biblioteca possui seu próprio módulo:

```go
// saudacao/saudacao.go
package saudacao

import "fmt"

func Ola(nome string) string {
	return fmt.Sprintf("Olá, %s!", nome)
}
```

```go
// saudacao/go.mod
module example.com/plataforma/saudacao

go 1.27
```

A API importa a biblioteca pelo caminho normal do módulo:

```go
// api/main.go
package main

import (
	"fmt"

	"example.com/plataforma/saudacao"
)

func main() {
	fmt.Println(saudacao.Ola("Gopher"))
}
```

```go
// api/go.mod
module example.com/plataforma/api

go 1.27

require example.com/plataforma/saudacao v0.0.0
```

A versão `v0.0.0` representa aqui uma dependência ainda não publicada. Na raiz `plataforma`, crie o workspace:

```bash
cd plataforma
go work init ./api ./saudacao
go run ./api
```

O comando gera um arquivo parecido com este:

```go
// go.work
go 1.27

use (
	./api
	./saudacao
)
```

A partir desse diretório ou de seus subdiretórios, o comando `go` encontra `go.work`, reconhece os dois módulos e usa a implementação local de `saudacao`.

## Comandos essenciais do go work

### `go work init`

Cria o arquivo inicial:

```bash
go work init
```

Você pode informar módulos no mesmo comando:

```bash
go work init ./api ./libs/auth ./libs/observabilidade
```

Os caminhos devem apontar para diretórios que possuem `go.mod`.

### `go work use`

Adiciona ou remove módulos da diretiva `use`:

```bash
go work use ./libs/pagamentos
go work use -r ./services
```

Com `-r`, o comando percorre recursivamente o diretório e adiciona os módulos encontrados. Isso é prático em um monorepo, mas revise o diff: incluir ferramentas, exemplos ou módulos experimentais sem intenção pode deixar todos os comandos mais amplos e lentos.

Para remover uma diretiva explicitamente, use `go work edit`:

```bash
go work edit -dropuse=./libs/legado
```

Outra opção é apagar ou mover o diretório e rodar `go work use` novamente: o comando remove entradas cujos módulos já não existem.

### `go work edit`

Edita o arquivo de forma programática. É útil em scripts que não devem manipular texto com `sed`:

```bash
go work edit -use=./libs/catalogo
go work edit -dropuse=./libs/legado
go work edit -json
```

A saída JSON ajuda ferramentas internas a inspecionar o workspace sem depender da formatação textual.

### `go work sync`

Sincroniza informações da lista de build do workspace com os módulos:

```bash
go work sync
```

Esse comando pode atualizar requisitos nos arquivos `go.mod` dos módulos. Por isso, não o trate como uma operação invisível: execute, revise os diffs e rode os testes. Ele não substitui o `go mod tidy` de cada módulo.

## Como o Go encontra o arquivo go.work

Ao executar um comando, o toolchain procura `go.work` no diretório atual e depois sobe pelos diretórios pais. Você pode confirmar qual arquivo está ativo com:

```bash
go env GOWORK
```

A saída pode ser:

```text
/home/ana/projetos/plataforma/go.work
```

Se não houver workspace ativo, o valor fica vazio ou indica que ele foi desabilitado, dependendo do ambiente.

Para ignorar o workspace em um único comando:

```bash
GOWORK=off go test ./...
```

Também é possível apontar explicitamente para um arquivo:

```bash
GOWORK=/tmp/workspaces/release.work go test ./...
```

O caminho explícito deve ser absoluto. Na prática, `GOWORK=off` é o caso mais importante: ele verifica se um módulo não depende acidentalmente do contexto local.

## go.work não substitui go.mod

O `go.mod` continua sendo a declaração do módulo. Ele informa:

- o caminho público do módulo;
- a versão mínima da linguagem e do toolchain aplicável;
- as dependências necessárias;
- exclusões, retrações ou substituições relevantes ao módulo.

O `go.work` informa quais **módulos principais locais** participam da operação atual. Ele não deve ser usado para esconder que uma aplicação esqueceu de declarar uma dependência.

Uma verificação útil é rodar os testes de duas maneiras:

```bash
# Integração com todos os módulos locais do workspace
go test ./...

# Módulo isolado, usando apenas seu go.mod
cd api
GOWORK=off go test ./...
```

O primeiro comando responde: “as mudanças locais funcionam juntas?”. O segundo responde: “o módulo publicado continua reproduzível sozinho?”. Em uma base com releases independentes, você precisa das duas respostas.

## go.work ou replace: qual escolher?

Uma diretiva `replace` no `go.mod` pode mapear um módulo para outro caminho ou versão:

```go
replace example.com/plataforma/saudacao => ../saudacao
```

Isso funciona, mas um caminho relativo local tem dois riscos:

- pode ser commitado por acidente e quebrar o build de outra pessoa;
- mistura uma conveniência do ambiente de desenvolvimento com o contrato do módulo.

O workspace evita esses problemas porque concentra a ligação local em `go.work`.

Use **`go.work`** quando a substituição existe porque você está desenvolvendo módulos juntos. Considere **`replace`** quando o próprio módulo precisa expressar uma troca controlada, por exemplo um fork temporário fixado em uma versão ou um caso de compatibilidade que deve valer para todos os colaboradores. Mesmo assim, documente a decisão e planeje sua remoção.

## O que é go.work.sum

Assim como um módulo pode ter `go.sum`, o workspace pode gerar `go.work.sum`. Ele registra hashes necessários para dependências usadas no contexto do workspace que não estejam cobertas pelos arquivos `go.sum` dos módulos.

Não edite esse arquivo manualmente. O comando `go` o mantém conforme resolve e baixa módulos.

Se o `go.work` é versionado, normalmente faz sentido avaliar o `go.work.sum` no mesmo contexto e mantê-lo versionado para reproduzir a resolução. Se o workspace é estritamente pessoal e está no `.gitignore`, o arquivo de soma correspondente também costuma ser ignorado.

## Devo commitar go.work?

Não existe uma resposta única. Use a propriedade do repositório como critério.

### Versione o workspace quando

- o repositório é um monorepo deliberado;
- os mesmos módulos devem ser usados juntos por toda a equipe;
- comandos e documentação assumem uma raiz comum;
- o CI testa o conjunto como workspace;
- a lista de módulos é parte da arquitetura do repositório.

### Ignore o workspace quando

- cada pessoa combina clones em caminhos diferentes;
- o arquivo serve apenas para testar uma mudança entre repositórios independentes;
- os módulos precisam ser validados prioritariamente como unidades isoladas;
- a lista local inclui forks ou experimentos pessoais;
- o repositório já definiu outra estratégia oficial de build.

Para ignorá-lo:

```gitignore
go.work
go.work.sum
```

A equipe Go alerta que versionar um `go.work` pode fazer o CI testar combinações de dependências locais diferentes daquelas que os consumidores realmente recebem. Isso não significa “nunca commite”. Significa que o workspace deve ser uma decisão de repositório, não um arquivo pessoal enviado sem revisão.

## Estratégia de CI para múltiplos módulos

Em um monorepo, execute uma camada integrada e uma camada isolada.

### 1. Teste integrado pelo workspace

Na raiz:

```bash
go test ./...
go vet ./...
```

Isso detecta incompatibilidades entre mudanças locais antes que as versões sejam publicadas.

### 2. Teste cada módulo com GOWORK=off

Um script simples pode localizar os módulos:

```bash
find . -name go.mod -not -path '*/vendor/*' -print0 |
while IFS= read -r -d '' mod; do
	dir=$(dirname "$mod")
	echo "==> testando $dir"
	(
		cd "$dir"
		GOWORK=off go test ./...
		GOWORK=off go vet ./...
	)
done
```

Assim, um módulo não passa no CI apenas porque outro módulo local forneceu uma dependência que ainda não foi publicada ou declarada corretamente.

Para suítes maiores, combine isso com as [flags do go test](/blog/go-test-flags-run-count-shuffle-race-json/) e mantenha `-race`, cobertura e testes de integração em jobs apropriados.

## Padrão prático para mudanças entre repositórios

Workspaces também ajudam fora de monorepos. Suponha dois clones vizinhos:

```text
~/codigo/
├── sdk-pagamentos/
└── checkout-api/
```

Crie um workspace fora dos repositórios:

```bash
mkdir -p ~/codigo/workspaces/checkout
cd ~/codigo/workspaces/checkout
go work init ../../sdk-pagamentos ../../checkout-api
```

Agora você pode mudar o SDK e testar a API contra o código local. Como o `go.work` ficou em uma pasta separada, nenhum dos repositórios precisa receber um arquivo temporário.

Antes de abrir os pull requests:

1. rode os testes integrados com o workspace;
2. rode `GOWORK=off go test ./...` em cada módulo;
3. publique ou faça merge da biblioteca na ordem necessária;
4. atualize a versão exigida pela aplicação;
5. remova qualquer dependência de uma versão fictícia usada apenas no experimento.

Esse fluxo reduz o intervalo entre “acho que as APIs combinam” e “testei o consumidor real”.

## Erros comuns com Go Workspaces

### Criar módulos demais

Separar cada pacote em um módulo gera releases, dependências e pipelines sem benefício. Pacotes dentro do mesmo módulo já podem ser importados normalmente. Comece com um módulo e extraia outro quando houver uma fronteira de distribuição real.

### Testar somente com o workspace ativo

O código passa localmente, mas falha depois de publicado porque o `go.mod` exige uma versão antiga. Sempre inclua uma validação com `GOWORK=off` quando os módulos têm vida independente.

### Usar `go.work` para esconder dependências ausentes

Se o código importa um módulo, o `go.mod` correspondente deve declarar a dependência adequada. O workspace não é licença para manter metadados incompletos.

### Commitar caminhos pessoais

Entradas como `/home/joao/fork` não funcionam na máquina de outra pessoa. Para workspaces compartilhados, prefira caminhos relativos dentro da estrutura do repositório.

### Rodar `go work sync` sem revisar o diff

A sincronização pode alterar requisitos nos módulos. Trate-a como qualquer comando que edita `go.mod`: revise, execute `go mod tidy` onde necessário e valide o build.

### Confundir workspace com ferramenta de release

O `go.work` ajuda a desenvolver módulos em conjunto, mas não define ordem de publicação, tags, changelog ou compatibilidade semântica. O release continua exigindo versões coerentes e dependências publicadas.

## Checklist para adotar go.work

1. Confirme que existem fronteiras reais entre os módulos.
2. Crie o workspace com `go work init` e `go work use`.
3. Verifique o arquivo ativo com `go env GOWORK`.
4. Rode testes integrados na raiz.
5. Rode testes isolados com `GOWORK=off` em cada módulo.
6. Decida explicitamente se `go.work` e `go.work.sum` entram no Git.
7. Evite `replace` com caminho local no `go.mod` publicado.
8. Documente o comando padrão de teste para a equipe.
9. Revise os diffs depois de `go work sync`.
10. Garanta que releases usem versões reais entre módulos.

## Perguntas frequentes

### Para que serve o arquivo go.work?

Ele reúne módulos locais em um workspace. Durante o desenvolvimento, imports entre esses módulos apontam para o código local, sem exigir uma versão publicada ou um `replace` temporário em cada `go.mod`.

### Devo commitar o go.work no Git?

Em um monorepo cujo fluxo oficial depende do workspace, pode fazer sentido. Para combinações pessoais de clones, forks locais ou módulos que devem funcionar isoladamente, normalmente é melhor ignorá-lo. Registre a escolha na documentação do repositório.

### Qual é a diferença entre go.work e replace?

`go.work` configura o ambiente de desenvolvimento que reúne módulos locais. `replace` altera a resolução declarada dentro de um `go.mod`. Caminhos locais em `replace` são fáceis de esquecer e prejudicam a reprodução em outras máquinas.

### O go.work substitui o go.mod?

Não. Cada módulo mantém seu próprio `go.mod`. O workspace apenas coordena quais módulos principais locais participam dos comandos atuais.

### Como desativar temporariamente um workspace?

Use `GOWORK=off` antes do comando:

```bash
GOWORK=off go test ./...
```

## Próximos passos

- [Go Modules na prática](/aprenda/go-modules-na-pratica/) — dependências, versões, `tidy` e organização do módulo;
- [Documentação Go em português](/aprenda/documentacao-go/) — como usar `go help`, `go doc` e fontes oficiais;
- [Flags do go test](/blog/go-test-flags-run-count-shuffle-race-json/) — filtre, repita e diagnostique testes no CI;
- [golangci-lint e Staticcheck](/blog/staticcheck-golangci-lint-go-qualidade-ci/) — mantenha a qualidade entre vários módulos;
- [GoReleaser](/blog/goreleaser-go-binarios-checksums-sbom/) — automatize releases quando módulos produzem CLIs ou binários;
- [Vagas de Go no Brasil](/vagas/) — acompanhe equipes que trabalham com serviços, plataformas e tooling em Go.

## Fontes oficiais

- [Tutorial oficial: Getting started with multi-module workspaces](https://go.dev/doc/tutorial/workspaces)
- [Referência de módulos: Workspaces](https://go.dev/ref/mod#workspaces)
- [Documentação do comando go work](https://pkg.go.dev/cmd/go#hdr-Workspace_maintenance)

Go Workspaces são mais úteis quando permanecem simples: **módulos continuam independentes, o workspace acelera o desenvolvimento conjunto e o CI verifica as duas realidades**. Se o time entende essa separação, `go.work` elimina versões provisórias e alterações locais frágeis sem transformar o monorepo em mágica difícil de reproduzir.
