Cómo se Estructuran los Programas Go: Paquetes, main y la Toolchain
Go organiza el código fuente en paquetes, los compila en archivos objeto y los enlaza en un único binario estático.
Busca en todas las páginas de la documentación
Go organiza el código fuente en paquetes, los compila en archivos objeto y los enlaza en un único binario estático.
Comprender ese proceso te ayuda a ubicar main, razonar sobre las importaciones y depurar fallos de compilación sin adivinar.
main, compilado por la toolchain de Go en un solo ejecutable sin un runtime separado que enviar.main package (paquete main), build cache (caché de compilación), linking (enlazado).go build o decidir dónde pertenecen init y main.go.mod, modo workspace, vendoring, compilación cruzada y la estructura de la biblioteca estándar.Los archivos fuente de Go pertenecen a exactamente un package, declarado al principio de cada archivo con package foo.
El nombre del paquete suele ser el último segmento de la import path (por ejemplo, import "net/http" usa el paquete http), pero no tiene por qué coincidir con el nombre del directorio en casos raros como package main.
Solo el main package produce un ejecutable.
Debe definir func main() como el punto de entrada del proceso.
Cada otro paquete es una biblioteca: se compila en un archivo (.a) que el enlazador combina en el binario final.
Un module es la unidad de versionado.
El archivo go.mod en la raíz del repositorio nombra la ruta del módulo (por ejemplo, example.com/myapp) y fija las versiones de las dependencias.
Las rutas de importación dentro de tu módulo comienzan con esa ruta de módulo más la ruta del directorio debajo de ella.
Piensa en la estructura como una pequeña línea de producción:
archivos fuente .go --> compilador go --> archivos .a --> enlazador --> binario único
La toolchain de Go (go command) orquesta la compilación, el enlazado, las pruebas y la descarga de módulos.
Rara vez invocas gc o ld directamente.
Cuando ejecutas go build, la herramienta resuelve el grafo de módulos desde go.mod, recorre las importaciones comenzando desde tu paquete main y compila cada paquete necesario.
Los resultados se guardan en la build cache bajo $GOPATH/pkg o la caché de módulos, de modo que los paquetes sin cambios omitan la recompilación.
Los identificadores exportados comienzan con una letra mayúscula; los nombres en minúscula son privados del paquete.
Esa regla la aplica el compilador, no los modificadores de acceso en el código fuente.
El enlazador realiza la eliminación de código muerto a nivel de función para el código inalcanzable, lo que mantiene los binarios más pequeños que enlazar ingenuamente cada símbolo.
// cmd/myapp/main.go - entrada ejecutable
package main
import "example.com/myapp/internal/server"
func main() {
server.Run()
}Los directorios internal/ son especiales: el compilador rechaza las importaciones de example.com/myapp/internal/... desde fuera del árbol example.com/myapp.
Eso te da un límite forzado para el código no público.
Las funciones init en un paquete se ejecutan antes que main, en orden de dependencia, y son principalmente para registro o configuración única.
El uso excesivo de init dificulta razonar sobre el orden de inicio.
go test compila archivos de prueba (*_test.go) en el mismo paquete (o package foo_test para pruebas de caja negra) y enlaza un binario de prueba que ejecuta funciones Test*.
Las mismas reglas de grafo de paquetes se aplican.
Los Workspaces (go.work) permiten que múltiples módulos se compilen juntos durante el desarrollo local sin publicar pseudo-versiones.
Úsalos cuando editas una biblioteca y su consumidor en paralelo.
La compilación cruzada establece GOOS y GOARCH; Go todavía emite un binario estático por defecto en la mayoría de las plataformas.
Las compilaciones habilitadas para CGO enlazan código C y complican las compilaciones cruzadas porque necesitan una toolchain C coincidente.
| Enfoque | Fortaleza | Debilidad | Mejor Ajuste |
|---|---|---|---|
| Monorepo, un módulo | Importaciones simples, un go.mod | Módulos grandes pueden ralentizar CI | Equipos pequeños, producto único |
| Módulo de biblioteca + módulo de aplicación | Límites claros de lanzamiento | Se necesita replace/workaround local | Bibliotecas compartidas entre productos |
Paquetes internal/ | Privacidad forzada por el compilador | No se puede compartir con importadores externos | Ayudantes específicos de la aplicación |
Vendoring (vendor/) | Compilaciones offline reproducibles | Mantenimiento manual o go mod vendor | Air-gapped o auditoría estricta |
Las imágenes de contenedor para Go a menudo solo copian go.mod, go.sum y el código fuente, ejecutan go build -o /app y envían una imagen scratch o distroless porque el binario no necesita JVM ni intérprete.
Los hooks de observabilidad (pprof, trace) se compilan en el mismo binario a través de importaciones en blanco o registro explícito en main.
package main y las importaciones renombradas (import http "net/http") rompen ese patrón.go run omite el paso de compilación - Compila a un binario temporal y lo ejecuta; no es un intérprete.unsafe aún pueden acceder a los datos.go.mod todavía registra las versiones.Un módulo es una unidad versionada declarada en go.mod (a menudo un repositorio).
Un paquete es una unidad de compilación dentro de ese módulo (generalmente un directorio de archivos .go).
En un paquete llamado main, típicamente bajo cmd/<nombre_app>/main.go en proyectos más grandes.
Solo un paquete main se enlaza por ejecutable.
La ruta del módulo en go.mod actúa como un prefijo globalmente único para que go get pueda obtener código de hosts VCS como GitHub o tu forge privado.
Fusiona los archivos de paquetes compilados, resuelve símbolos, aplica eliminación de código muerto y escribe un ejecutable nativo para el sistema operativo y arquitectura de destino.
Todas las funciones init en los paquetes importados se ejecutan primero, en orden de dependencia, luego se ejecuta main.main.
Múltiples funciones init en un archivo se ejecutan en orden de código fuente.
Los ciclos de importación se rechazan en tiempo de compilación.
Refactoriza tipos compartidos en un tercer paquete o estrecha interfaces para romper el ciclo.
Go trata las rutas de importación .../internal/... como privadas para el árbol padre por encima de internal.
Los módulos externos no pueden importarlos.
Las compilaciones puras de Go se enlazan estáticamente por defecto.
Las importaciones de CGO o ciertos wrappers de syscall pueden incluir bibliotecas dinámicas dependiendo de la plataforma y las etiquetas de compilación.
Los resultados de los paquetes compilados se indexan por hashes de código fuente y flags.
Los paquetes sin cambios reutilizan archivos .a cacheados en lugar de recompilar.
cmd/ contiene múltiples paquetes main (herramientas CLI, workers) mientras que el código de biblioteca permanece importable en la raíz del módulo o bajo pkg/ por convención.
Go selecciona la versión mínima que satisface todos los requisitos (MVS).
Ves una versión en go.mod a menos que uses replaces para excepciones.
Los módulos reemplazaron a GOPATH para la gestión de dependencias.
GOPATH todavía define las ubicaciones predeterminadas de la caché de módulos y los artefactos de compilación, pero no pones código fuente allí para el trabajo normal basado en módulos.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado Green Tea GC, modernizadores go fix - verificar parche en la compilación), chi (última versión - verificar en la compilación), gin (última versión - verificar en la compilación), echo (última versión - verificar en la compilación), google.golang.org/grpc (última versión - verificar en la compilación), sigs.k8s.io/controller-runtime (última versión - verificar en la compilación), kubebuilder (última versión - verificar en la compilación), tinygo (última versión - verificar objetivos de placa en la compilación), wazero (última versión - verificar en la compilación) y golangci-lint (última versión - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026