O que é Package em Go?
Um package (pacote) em Go é a unidade fundamental de organização e reutilização de código. Todo arquivo .go pertence a exatamente um pacote, declarado na primeira linha do arquivo. Packages agrupam funções, tipos, variáveis e constantes relacionados em uma unidade coesa, promovendo encapsulamento e separação de responsabilidades.
O sistema de pacotes de Go é uma das razões pela qual a linguagem é conhecida pela simplicidade e velocidade de compilação. Diferente de linguagens com includes ou headers, Go usa importações explícitas com caminhos únicos, eliminando ambiguidade e permitindo compilação paralela eficiente de pacotes independentes.
Na standard library, você já usa pacotes constantemente: fmt para formatação, net/http para servidores web, encoding/json para serialização, os para operações do sistema. Cada um encapsula funcionalidade específica com uma API clara e documentada.
Package declaration
Todo arquivo Go começa com a declaração do pacote ao qual pertence:
package main // pacote executável
package handlers // pacote de biblioteca
Regras fundamentais
- Todos os arquivos em um mesmo diretório devem declarar o mesmo pacote
- O nome do pacote geralmente corresponde ao último elemento do caminho de importação
- Apenas o pacote
mainpode conter a funçãomain()— ponto de entrada do programa - Testes usam o mesmo pacote ou
nome_testpara testes de caixa-preta
meu-projeto/
├── main.go // package main
├── handlers/
│ ├── user.go // package handlers
│ └── product.go // package handlers
├── models/
│ └── user.go // package models
└── utils/
└── helpers.go // package utils
O pacote main
O pacote main tem tratamento especial em Go — é o ponto de entrada de um programa executável:
package main
import "fmt"
func main() {
fmt.Println("Olá, mundo!")
}
Sem package main e func main(), o compilador não gera um binário executável. Packages que não são main são bibliotecas — fornecem funcionalidade para outros pacotes importarem.
Ao construir CLIs com Cobra ou APIs REST, o pacote main geralmente é mínimo, delegando lógica para pacotes internos.
Imports
Sintaxe de import
// Import único
import "fmt"
// Múltiplos imports (forma preferida)
import (
"context"
"fmt"
"net/http"
"github.com/gorilla/mux"
"meu-projeto/internal/handlers"
)
Convenção de agrupamento
A convenção da comunidade Go é agrupar imports em blocos separados por linha em branco:
- Standard library — pacotes da biblioteca padrão
- Terceiros — dependências externas
- Internos — pacotes do próprio projeto
O goimports (e a maioria das IDEs) formata automaticamente nessa ordem.
Import com alias
import (
"crypto/rand"
mathrand "math/rand" // alias para evitar conflito
log "github.com/sirupsen/logrus" // alias mais curto
)
Import para side effects
import (
_ "image/png" // registra decoder PNG
_ "github.com/lib/pq" // registra driver PostgreSQL
_ "net/http/pprof" // registra handlers de profiling
)
O blank identifier _ importa o pacote apenas para executar suas funções init(), sem usar diretamente nenhum símbolo exportado.
Exported vs Unexported (Visibilidade)
Go usa uma regra simples e elegante para controle de visibilidade:
- Letra maiúscula = exportado (público) — acessível fora do pacote
- Letra minúscula = não exportado (privado) — acessível apenas dentro do pacote
package usuario
// Exportado — visível por outros pacotes
type Usuario struct {
Nome string // exportado
Email string // exportado
senha string // NÃO exportado — apenas dentro do pacote usuario
}
// Exportado
func NovoUsuario(nome, email, senha string) *Usuario {
return &Usuario{
Nome: nome,
Email: email,
senha: hashSenha(senha),
}
}
// Não exportado — função interna
func hashSenha(s string) string {
// implementação interna
return s
}
Essa convenção se aplica a funções, tipos, variáveis, constantes, métodos e campos de struct. Não existe keyword public/private — a capitalização é o mecanismo.
Go Modules
Go Modules é o sistema oficial de gerenciamento de dependências desde Go 1.11+:
# Inicializar módulo
go mod init github.com/usuario/projeto
# Adicionar dependência
go get github.com/gorilla/mux@v1.8.1
# Atualizar dependências
go get -u ./...
# Limpar dependências não usadas
go mod tidy
go.mod
module github.com/usuario/meu-api
go 1.22
require (
github.com/gorilla/mux v1.8.1
github.com/lib/pq v1.10.9
)
go.sum
Contém hashes criptográficos de todas as dependências para garantir integridade e reprodutibilidade. Sempre comite go.sum no controle de versão.
Para um guia completo, veja Go Modules na prática e o guia de módulos.
Internal packages
O diretório internal é um mecanismo especial de Go para restringir visibilidade de pacotes:
meu-projeto/
├── cmd/
│ └── api/
│ └── main.go
├── internal/ ← pacotes aqui são privados ao módulo
│ ├── database/
│ │ └── postgres.go
│ ├── middleware/
│ │ └── auth.go
│ └── service/
│ └── user.go
├── pkg/ ← pacotes aqui são públicos (importáveis)
│ └── validator/
│ └── email.go
└── go.mod
Pacotes dentro de internal/ só podem ser importados por código dentro do mesmo módulo (ou módulo pai). Tentativas externas de importar causam erro de compilação — é o encapsulamento a nível de módulo.
Convenções de nomenclatura
Nomes de pacotes
- Minúsculas, singular:
user, nãousersouUser - Curtos e descritivos:
http,json,auth - Sem underscores ou camelCase:
strconv, nãostr_convoustrConv - Evite nomes genéricos:
utils,common,helpers(anti-pattern)
O nome do pacote faz parte da API
Os símbolos exportados são prefixados pelo nome do pacote no uso:
// Ruim — redundância
package user
type UserService struct{} // user.UserService ← redundante!
// Bom — conciso
package user
type Service struct{} // user.Service ← claro!
// Ruim
package http
func HTTPServeHTTP() {} // http.HTTPServeHTTP ← terrível
// Bom (standard library real)
func ListenAndServe() error {} // http.ListenAndServe ← limpo
Função init()
Cada pacote pode ter uma ou mais funções init() que executam automaticamente antes de main():
package database
import "database/sql"
var db *sql.DB
func init() {
var err error
db, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
}
A ordem de execução é:
- Variáveis de pacote são inicializadas
- Funções
init()executam (na ordem de declaração dentro do arquivo, e em ordem de importação entre pacotes) main()executa
Use init() com parcimônia — excesso de lógica em init dificulta testes e torna dependências implícitas.
Organização de projetos Go
A comunidade converge para o seguinte layout:
projeto/
├── cmd/ # pontos de entrada (main packages)
│ ├── api/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/ # código privado do módulo
│ ├── handler/
│ ├── service/
│ ├── repository/
│ └── model/
├── pkg/ # código público reutilizável
├── api/ # specs OpenAPI, protobufs
├── configs/ # configurações
├── migrations/ # SQL migrations
├── go.mod
└── go.sum
Para mais detalhes sobre arquitetura em Go, veja o tutorial de Clean Architecture e o guia de microsserviços com Go.
Boas práticas com packages
- Um pacote = uma responsabilidade — coesão alta, acoplamento baixo
- Evite pacotes genéricos como
utils— distribua funções nos pacotes que as usam - Use
internal/para proteger implementação de uso externo - Documente pacotes exportados com godoc comments
- Mantenha imports limpos — rode
goimportsougciregularmente - Minimize dependências — cada import é uma responsabilidade
Aprenda mais sobre organização de código com o guia de Go para iniciantes e as melhores IDEs para Go que facilitam refatoração de pacotes.
Perguntas frequentes (FAQ)
Qual a diferença entre pacote e módulo em Go?
Um pacote é um diretório com arquivos .go que compartilham a mesma declaração package. Um módulo é uma coleção de pacotes versionados juntos, definido por um arquivo go.mod. Um módulo contém um ou mais pacotes. Exemplo: github.com/gorilla/mux é um módulo com o pacote mux.
Por que meu símbolo não é acessível de outro pacote?
Em Go, apenas símbolos que começam com letra maiúscula são exportados (visíveis fora do pacote). Se uma função, tipo ou variável começa com minúscula, é privada ao pacote. Renomeie para iniciar com maiúscula para exportar: processar → Processar.
Posso ter múltiplos arquivos no mesmo pacote?
Sim. Todos os arquivos .go em um mesmo diretório devem declarar o mesmo pacote e formam juntos a unidade compilada. Você pode dividir livremente structs, funções e interfaces entre arquivos — o compilador junta tudo. Use arquivos separados para organização lógica (ex: user.go, user_repository.go, user_service.go).
Quando usar o diretório internal/ vs pkg/?
Use internal/ para código que é detalhe de implementação do seu projeto — ninguém externo deve importar. Use pkg/ para código que você deliberadamente quer que outros projetos possam reutilizar. Na dúvida, comece com internal/ — é mais fácil mover para pkg/ depois do que o contrário. Muitos projetos modernos nem usam pkg/, colocando tudo em internal/.