Go多模块结构按业务边界、复用性、发布节奏和依赖隔离划分,每个go.mod对应独立构建、版本化、测试和发布的单元;核心原则包括提供稳定API、高频复用、独立发布周期、解耦编译部署或跨团队维护需求。

Go 多模块(multi-module)结构不是靠目录“看起来多”,而是按业务边界、复用性、发布节奏和依赖隔离来划分 module,每个 go.mod 对应一个可独立构建、版本化、测试和发布的单元。
模块划分的核心原则
一个 module 应该满足以下至少一条:
- 对外提供稳定 API,被其他项目或模块频繁复用(如通用工具库、客户端 SDK)
- 有独立的发布周期(比如
api每周发版,worker每月发版) - 需要与其他模块解耦编译或部署(例如 CLI 工具和后台服务共用部分逻辑,但不想强绑定)
- 存在不同团队维护、不同权限控制或不同 CI/CD 流程的需求
典型目录结构示例(推荐)
以企业级后台服务为例:
myproject/ ├── go.mod # 根 module,仅声明 proxy / replace,不写 require ├── cmd/ │ ├── api/ │ │ ├── main.go │ │ └── go.mod # api module:HTTP 服务入口,依赖 internal/api + internal/core │ ├── worker/ │ │ ├── main.go │ │ └── go.mod # worker module:异步任务入口,依赖 internal/worker + internal/core │ └── cli/ │ ├── main.go │ └── go.mod # cli module:命令行工具,轻量依赖 internal/core ├── internal/ │ ├── core/ # 共享核心逻辑(domain/entity/usecase),无外部依赖 │ │ └── go.mod │ ├── api/ # HTTP 层专用逻辑(handler/middleware),依赖 core │ │ └── go.mod │ ├── worker/ # 任务调度/执行逻辑,依赖 core + third-party job queue │ │ └── go.mod │ └── storage/ # 数据访问层(repo/db/cache),可选单独 module │ └── go.mod ├── pkg/ # 可被外部引用的公共包(如 auth/jwt/logutil) │ ├── jwt/ │ │ └── go.mod # 独立 module,语义化版本,支持 go get │ └── logutil/ │ └── go.mod └── scripts/ # 构建/发布脚本,不参与 go build
注意:根目录 go.mod 不写 require,只用于设置 GO111MODULE=on 环境下的代理或替换规则;各子 module 的 go.mod 自行管理依赖。
module 间依赖与版本管理
内部 module 之间用相对路径 replace 开发,发布时改用语义化版本:
- 开发阶段,在
cmd/api/go.mod中写:replace github.com/yourorg/myproject/internal/core => ../internal/core - 发布
pkg/jwt后打 tagv1.2.0,其他 module 就用:require github.com/yourorg/myproject/pkg/jwt v1.2.0 - 避免循环依赖:module A 不能直接 import module B,同时 B 又 import A;可通过提取公共 interface 到
core或pkg解耦
CI/CD 与构建建议
多 module 不等于每个 module 都要单独 CI:
- 对
cmd/下的服务类 module,建议独立构建镜像、独立部署 - 对
internal/下的 module,不单独发布,只在本地构建时被引用;CI 中可跳过测试或仅做单元测试 - 对
pkg/下的公共 module,应启用完整 CI(test + lint + version bump + push to proxy) - 使用
go list -m ./...快速列出当前工作区所有 module,配合脚本批量操作
基本上就这些。多 module 结构不复杂,但容易忽略边界定义和 replace 管理,关键是让每个 go.mod 有明确的“谁用它、为什么独立、怎么升级”——而不是为了分而分。









