Модули в Go: go mod init, зависимости и типичные грабли
Go-модули — единственный поддерживаемый способ управлять зависимостями начиная с Go 1.16. Разбираем, как инициализировать модуль, подключать пакеты, фиксировать версии и не наступить на грабли с заменами и приватными репозиториями.

Зачем вообще модули, если раньше был GOPATH
До Go 1.11 весь код жил в одном дереве GOPATH: ни версий, ни изоляции, ни воспроизводимых сборок. Два проекта, которым нужны разные версии одной библиотеки, мешали друг другу. Модули решили три проблемы разом: проект хранит точный список зависимостей с хешами (go.sum), версии подчиняются семантическому версионированию, а сам проект может лежать где угодно на диске.
Начиная с Go 1.16 модульный режим включён по умолчанию, а с Go 1.22 переменная GO111MODULE уже не влияет на поведение — модули единственный путь. Всё, что описано ниже, проверено на Go 1.22.x; для более ранних версий синтаксис команд совпадает, но детали резолвинга могут отличаться.
Что нужно до начала
- Go 1.18 или новее (рекомендуется 1.22+). Проверьте:
go version. - Доступ в интернет или настроенный
GOPROXYдля приватных пакетов. - Git — большинство модулей хостится на GitHub/GitLab, и
go getиспользует Git под капотом.
Инициализация модуля: go mod init
Команда go mod init создаёт файл go.mod — манифест модуля. Единственный обязательный аргумент — путь модуля. Он же станет корневым import-path для всех пакетов внутри.
# Создаём каталог проекта и переходим в него
mkdir myservice && cd myservice
# Инициализируем модуль
go mod init github.com/yourname/myservice
После выполнения в каталоге появится файл go.mod с двумя строками:
module github.com/yourname/myservice
go 1.22
Как выбрать путь модуля. Если проект публичный — используйте реальный URL репозитория. Если внутренний и никогда не будет импортироваться извне, подойдёт любой путь: company.internal/backend, example.com/tool. Главное — этот путь нельзя поменять без переписывания всех импортов.
Проверка. Файл go.mod существует, cat go.mod показывает путь и версию Go.
Добавляем зависимости
Через go get
Самый явный способ — запросить конкретный пакет:
# Последняя стабильная версия
go get github.com/rs/zerolog
# Конкретная версия
go get github.com/rs/zerolog@v1.32.0
# Конкретный коммит (полезно для форков)
go get github.com/rs/zerolog@af3c6d5
Go скачает модуль, обновит go.mod (строка require) и go.sum (хеши).
Через импорт и go mod tidy
Можно просто написать import в коде, а потом выполнить:
go mod tidy
Команда добавит недостающие модули, удалит неиспользуемые и пересчитает go.sum. Это предпочтительный способ в повседневной работе: вы пишете код, а tidy синхронизирует манифест.
Что попадает в go.mod и go.sum
| Файл | Что хранит | Коммитить? |
|---|---|---|
go.mod | Путь модуля, версия Go, прямые и косвенные зависимости, замены | Да, обязательно |
go.sum | Криптографические хеши каждой версии каждого модуля | Да, обязательно |
Оба файла — часть репозитория. Без go.sum воспроизводимая сборка невозможна: Go проверяет хеши при каждом скачивании.
Версионирование и MVS
Go использует алгоритм Minimal Version Selection (MVS). Если модуль A требует пакет X v1.2.0, а модуль B — X v1.3.0, Go выберет v1.3.0 — минимальную версию, удовлетворяющую всем ограничениям. Никогда не выберет v1.4.0, даже если она существует, пока её не попросят явно.
MVS — одно из самых непривычных решений в Go-экосистеме. В npm и pip резолвер пытается выбрать максимально свежую совместимую версию; Go делает ровно наоборот. Это убирает целый класс поломок вида «вчера собиралось, сегодня нет» — но мешает автоматически получать патчи безопасности.
Major-версии — отдельные модули. Если библиотека выпустила v2, её import-path обязан содержать суффикс /v2:
import "github.com/example/lib/v2/pkg"
Это позволяет использовать v1 и v2 одновременно в одном проекте — приём, который в других экосистемах требует алиасов или хаков.
Сноска: Семантическое версионирование (semver) — соглашение о формате версий MAJOR.MINOR.PATCH, где MAJOR растёт при несовместимых изменениях API, MINOR — при добавлении функциональности с сохранением обратной совместимости, PATCH — при исправлении ошибок.
Замены и исключения
Директива replace
Иногда нужно подменить модуль: вы правите баг в библиотеке локально, используете форк или разрабатываете два модуля параллельно. Для этого в go.mod есть replace:
// Подменить удалённый модуль локальной копией
replace github.com/rs/zerolog => ../zerolog-fork
// Подменить одну версию конкретным форком
replace github.com/rs/zerolog v1.32.0 => github.com/yourname/zerolog v1.32.1-fix
Важно: replace работает только в go.mod корневого модуля. Если вы — библиотека, которую импортируют другие, ваши замены для них не действуют.
Директива exclude
Позволяет запретить конкретную версию модуля — полезно, если в ней известный баг:
exclude github.com/example/lib v1.5.0
Go выберет следующую подходящую версию по MVS.
Приватные модули и GOPROXY
По умолчанию Go загружает модули через прокси https://proxy.golang.org. Приватные репозитории там не лежат, и запрос упадёт с ошибкой 410 или таймаутом. Чтобы Go ходил за ними напрямую:
# Через переменную окружения
export GONOSUMCHECK="gitlab.company.com/*"
export GOPRIVATE="gitlab.company.com/*"
GOPRIVATE одновременно выставляет GONOSUMCHECK и GONOPROXY для указанных путей. Если у вас корпоративный прокси модулей (Athens, Goproxy), настройте GOPROXY на его адрес.
Типичные ошибки и что с ними делать
go: cannot find module providing package ...— обычно забылиgo mod tidyили опечатались в import-path. Проверьте регистр: Go чувствителен к нему, а GitHub — нет.ambiguous import— два разных модуля экспортируют один и тот же пакетный путь. Часто возникает при переезде репозитория. Решение:replaceстарого пути на новый.verifying ... checksum mismatch— хеш модуля вgo.sumне совпадает с тем, что скачал прокси. Причины: автор перезалил тег (retagging), или прокси закешировал другую ревизию. Удалите строку изgo.sum, выполнитеgo mod tidy. Если повторяется — подозрение на компрометацию, разбирайтесь отдельно.module declares its path as X, but was required as Y— чаще всего форк, в котором не поменялиmodule-строку вgo.mod. Исправьтеgo.modфорка или используйтеreplace.- Зависимость тянет старую версию Go — в
go.modзависимости указанаgo 1.17, ваш —go 1.22. Обычно проблем не создаёт, но если зависимость использует//go:build-теги новее своей заявленной версии, сборка сломается. Обновите зависимость или форкните.
Полезные команды на каждый день
| Команда | Что делает |
|---|---|
go mod tidy | Синхронизирует go.mod и go.sum с реальными импортами |
go mod download | Скачивает все зависимости в локальный кеш (полезно для Docker-сборок) |
go mod verify | Проверяет хеши скачанных модулей по go.sum |
go mod graph | Печатает граф зависимостей в формате «модуль → модуль» |
go mod why -m <module> | Показывает цепочку импортов, из-за которой модуль оказался в зависимостях |
go list -m all | Все модули, участвующие в сборке, с версиями |
go get -u ./... | Обновляет все прямые зависимости до последних minor/patch-версий |
Что делать дальше
Модуль инициализирован, зависимости подключены — следующий шаг зависит от контекста:
- CI/CD. Добавьте
go mod downloadотдельным шагом перед сборкой — он кешируется между запусками и ускоряет пайплайн. - Docker. Копируйте
go.modиgo.sumотдельным слоем до копирования кода: Docker закеширует слой с зависимостями, и пересборка после изменения одного файла не будет скачивать всё заново. - Безопасность. Запускайте
govulncheck ./...(отдельный инструмент от команды Go) — он проверяет зависимости по базе известных уязвимостей и показывает, затронут ли именно ваш код-path. - Обновления. Периодически запускайте
go get -u ./...и прогоняйте тесты. MVS не обновляет зависимости сам — это осознанное решение, но оно перекладывает ответственность за свежесть патчей на вас.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: Go Modules Reference — официальная документация, Tutorial: Getting started with multi-module workspaces — Go Blog
Частые вопросы
Можно ли использовать go mod init без указания пути модуля?
Чем go get отличается от go install?
Зачем коммитить go.sum, он же огромный?
Что делать, если go mod tidy удаляет нужную зависимость?
Как откатить зависимость на старую версию?
Можно ли держать несколько модулей в одном репозитории?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.