Un módulo es un árbol de directorios de paquetes Go con un archivo go.mod en la raíz. go.mod da nombre al módulo y enumera las versiones de todos los demás módulos de los que depende. Se crea con go mod init:
mkdir myapp
cd myapp
go mod init example.com/myapp
go: creating new go.mod: module example.com/myapp
El go.mod resultante:
module example.com/myapp
go 1.24.5
Con eso basta para compilar. Todo proyecto Go desde Go 1.16 es un módulo, y go build, go run . y go test se niegan a funcionar sin uno:
go: go.mod file not found in current directory or any parent directory; see 'go help modules'
Elegir la ruta del módulo
La ruta del módulo es el prefijo de cada ruta de import dentro del módulo. Con el módulo example.com/myapp, un paquete del directorio internal/store se importa como example.com/myapp/internal/store.
| Situación | Ruta del módulo |
|---|---|
| Código alojado en GitHub que otros pueden importar | github.com/yourname/project |
| Código de tu empresa | yourcompany.com/project o la URL del repositorio |
| Un programa privado o un ejercicio | example.com/myapp o simplemente myapp |
| Versión 2 o posterior de un módulo publicado | github.com/yourname/project/v2 |
En una librería, la ruta tiene que coincidir con dónde vive el código, porque go get la usa para encontrar el repositorio. En un programa que solo ejecutas tú, la ruta es solo un nombre. Evita una sola palabra que coincida con un paquete de la librería estándar, como go mod init fmt o go mod init strings: la compilación falla entonces con ambiguous import: found package fmt in multiple modules.
Ejecutar go mod init sin argumentos falla fuera de la antigua estructura de GOPATH:
go: cannot determine module path for source directory /home/ana/myapp (outside GOPATH, module path must be specified)
Dale una ruta.
Añadir dependencias
Escribe el import y deja que Go lo descargue. Supón que main.go importa github.com/google/uuid. Compilar antes de que el módulo lo conozca da una instrucción clara:
main.go:6:2: no required module provides package github.com/google/uuid; to add it:
go get github.com/google/uuid
Cualquiera de estos comandos lo arregla:
go get github.com/google/uuid
# or, to sync go.mod with every import in the module:
go mod tidy
go get informa de lo que cambió:
go: downloading github.com/google/uuid v1.6.0
go: added github.com/google/uuid v1.6.0
go mod tidy informa de cómo resolvió el import:
go: finding module for package github.com/google/uuid
go: downloading github.com/google/uuid v1.6.0
go: found github.com/google/uuid in github.com/google/uuid v1.6.0
go.mod tiene ahora una línea require:
module example.com/myapp
go 1.24.5
require github.com/google/uuid v1.6.0
go get con versiones
| Comando | Efecto |
|---|---|
go get pkg | añade pkg en su última versión publicada, o mantiene la actual si ya es un requisito |
go get pkg@v1.5.0 | usa exactamente v1.5.0 (sube o baja de versión) |
go get pkg@latest | pasa a la última versión publicada |
go get pkg@abc1234 | usa un commit concreto (se guarda como pseudo-versión) |
go get -u ./... | sube cada dependencia a su última versión menor o de parche |
go get -u=patch ./... | sube solo a las últimas versiones de parche |
go get pkg@none | quita el requisito |
go get go@1.24 | sube la versión mínima de Go del módulo |
go get cambia go.mod. Ya no compila ni instala programas; desde Go 1.18 eso es tarea de go install pkg@version.
Dependencias indirectas
Los requisitos marcados con // indirect son módulos que tu código no importa directamente pero que la compilación necesita. Desde Go 1.17, go.mod enumera cada módulo que aporta un paquete a la compilación, así que las dependencias de tus dependencias aparecen aquí con esa marca. go mod tidy gestiona estas marcas; no las añades tú.
go mod tidy
Ejecuta go mod tidy cada vez que añadas o quites imports. Hace lo siguiente:
- añade los requisitos de los paquetes importados que faltan,
- quita los requisitos que ya nada importa,
- añade las entradas de
go.sumque necesita la compilación y elimina las obsoletas.
Revisa todos los paquetes del módulo, incluidos los tests y todas las combinaciones de build tags, así que a veces mantiene una dependencia que no ves usada en tu plataforma. Ejecutar go mod tidy antes de cada commit, y comprobar en CI que no produce diferencias, mantiene go.mod fiel a la realidad.
go.sum
go.sum registra un hash por cada versión de módulo que usa la compilación:
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
La primera línea es el hash de los archivos del módulo; la segunda, solo el de su go.mod. Cuando el comando go descarga un módulo, comprueba el hash contra go.sum y contra la base de datos pública de checksums (sum.golang.org), así que una versión manipulada o cambiada en silencio hace fallar la compilación. Sube go.sum junto a go.mod y nunca lo edites a mano.
Cómo elige Go las versiones
Go usa selección de versión mínima (minimal version selection). Cada módulo enumera la versión mínima que necesita de cada dependencia, y la compilación usa la más alta de esas mínimas, nunca una más nueva. Si tu módulo requiere uuid v1.5.0 y una dependencia requiere uuid v1.6.0, la compilación usa v1.6.0, aunque exista v1.7.0. Nada se actualiza salvo que alguien lo pida con go get.
La consecuencia es que las compilaciones son reproducibles sin archivo de bloqueo: go.mod más el grafo de dependencias determinan por completo cada versión. go list -m all imprime el resultado:
go list -m all
example.com/myapp
github.com/google/uuid v1.6.0
Versiones mayores
Un módulo en v2 o superior tiene que incluir la versión mayor en su ruta: github.com/yourname/project/v2. La ruta de import cambia con ella, así que project y project/v2 son módulos distintos y pueden estar los dos en la misma compilación. Es la regla de Go para los cambios incompatibles, y por eso ves imports como github.com/jackc/pgx/v5.
replace: trabajar en una dependencia en local
Para probar cambios en una dependencia antes de publicarlos, apunta su ruta a un directorio local:
module example.com/myapp
go 1.24.5
require example.com/mylib v1.2.0
replace example.com/mylib => ../mylib
O desde la línea de comandos:
go mod edit -replace example.com/mylib=../mylib
go mod tidy
El directorio tiene que contener su propio go.mod. replace solo se aplica al compilar este módulo directamente, no cuando otro depende de él, así que acuérdate de quitarlo antes de etiquetar una versión.
Para editar varios módulos a la vez sin tocar sus archivos go.mod, Go 1.18 añadió los workspaces:
go work init . ../mylib
Eso escribe un archivo go.work que hace que el mylib local tenga prioridad. Deja go.work fuera del control de versiones salvo que todo el equipo use la misma estructura.
Dependencias de herramientas (Go 1.24)
Go 1.24 añadió la directiva tool, para que los generadores de código y los linters se versionen en go.mod en lugar de instalarse de forma global:
go get -tool golang.org/x/tools/cmd/stringer
go tool stringer -type=Color
func init es otra cosa
Las búsquedas de "golang init" suelen referirse a la función init, que no tiene nada que ver con go mod init. Cualquier paquete puede declarar func init(). No recibe argumentos, tu código no puede llamarla y se ejecuta una vez, automáticamente, después de asignar las variables a nivel de paquete y antes de main:
Un archivo puede tener varias funciones init, y se ejecutan en el orden en que aparecen. Los paquetes importados terminan antes su propia inicialización. Mantén init pequeña: el trabajo que puede fallar es más fácil de manejar y testear como una función normal llamada desde main.
Módulos privados y proxies
Por defecto, go descarga los módulos a través de proxy.golang.org. Ese proxy no ve los repositorios privados, así que dile a Go qué rutas son privadas:
go env -w GOPRIVATE=github.com/yourcompany/*
Los módulos que coinciden con GOPRIVATE se descargan directamente del repositorio con tus credenciales de git y se saltan la base de datos de checksums.
Preguntas frecuentes
¿Qué hace go mod init?
Crea un archivo go.mod en el directorio actual, lo que convierte ese directorio en la raíz de un módulo. go mod init example.com/myapp escribe la ruta del módulo y la versión de Go:
module example.com/myapp
go 1.24.5
Ejecútalo una vez por proyecto, antes de go build o go get.
¿Qué uso como ruta del módulo en go mod init?
La dirección desde la que se descargará el código si otros lo importan, normalmente la ruta del repositorio: go mod init github.com/yourname/project. Para un programa que nadie va a importar, sirve cualquier nombre (go mod init myapp), pero una ruta con estilo de dominio y punto como example.com/myapp evita choques con los nombres de paquetes de la librería estándar.
¿Qué diferencia hay entre go get y go mod tidy?
go get pkg@version añade una dependencia o cambia su versión. go mod tidy lee tus archivos fuente, añade cualquier módulo que tus imports necesiten y falte en go.mod, quita los requisitos que nada importa y actualiza go.sum. Un flujo habitual es escribir el import y luego ejecutar go mod tidy.
¿Debo subir go.sum al repositorio?
Sí. go.sum guarda hashes criptográficos de cada versión de módulo que usa tu build. Subirlo permite al comando go verificar que todo el mundo descarga dependencias idénticas byte a byte. Nunca lo edites a mano; go mod tidy lo mantiene.
¿"golang init" es lo mismo que go mod init?
No, son cosas distintas que comparten una palabra. go mod init es un comando de terminal que crea go.mod. func init() es una función que escribes en código Go; se ejecuta automáticamente una vez, antes de main, después de inicializar las variables del paquete.