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

  1. Todos os arquivos em um mesmo diretório devem declarar o mesmo pacote
  2. O nome do pacote geralmente corresponde ao último elemento do caminho de importação
  3. Apenas o pacote main pode conter a função main() — ponto de entrada do programa
  4. Testes usam o mesmo pacote ou nome_test para 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:

  1. Standard library — pacotes da biblioteca padrão
  2. Terceiros — dependências externas
  3. 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ão users ou User
  • Curtos e descritivos: http, json, auth
  • Sem underscores ou camelCase: strconv, não str_conv ou strConv
  • 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 é:

  1. Variáveis de pacote são inicializadas
  2. Funções init() executam (na ordem de declaração dentro do arquivo, e em ordem de importação entre pacotes)
  3. 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

  1. Um pacote = uma responsabilidade — coesão alta, acoplamento baixo
  2. Evite pacotes genéricos como utils — distribua funções nos pacotes que as usam
  3. Use internal/ para proteger implementação de uso externo
  4. Documente pacotes exportados com godoc comments
  5. Mantenha imports limpos — rode goimports ou gci regularmente
  6. 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: processarProcessar.

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/.