composer多仓库配置严格按repositories数组顺序匹配,命中即停;私有源须置顶、镜像源url须以/结尾、禁用默认源需单独成项且放最后,type字段决定行为不可混用。

Composer 多仓库配置不是“加几个 URL 就能自动 fallback”,而是严格按顺序匹配、命中即停。配错顺序或类型,composer require 会直接报 Could not find package,连私有包都拉不下来。
repositories 数组顺序就是优先级,没有其他机制
Composer 不识别 priority 字段(除非你用的是极老的插件),它只认 repositories 数组的书写顺序:从上到下扫描,第一个能提供目标包完整元数据的仓库就生效,后面的全跳过。
- 私有 Composer 仓库(如 Satis、Private Packagist)必须放在数组最前面,否则
acme/utils可能被 packagist.org 上同名但不同内容的包覆盖 - 镜像源(如阿里云、腾讯云)要写成
"type": "composer",URL 必须以/结尾(例如https://mirrors.aliyun.com/composer/),否则composer install可能静默失败 - 禁用默认源必须单独成项:
{"packagist.org": false},且建议放最后——放中间会提前截断查找,导致后面镜像也失效
type 字段决定仓库行为,混用会导致不生效
type 不是可选字段,它决定了 Composer 怎么用这个仓库。常见类型不能混着当“通用源”使:
-
"type": "composer":对应完整 Packagist 镜像,含packages.json,支持全局搜索和版本解析 -
"type": "vcs":只对require中显式写的包名生效,不会参与包发现;dev-main分支不会自动映射为dev-main版本,必须在require里写死"myorg/pkg": "dev-main" -
"type": "package":手动声明单个包的元数据,适合 Git 地址不想暴露给所有开发者时;但不支持dev-main别名,必须写死语义化版本(如"1.2.0")
错误示例:{"type":"vcs","url":"https://git.example.com/pkg"} 放在 repositories 里,却期望它能 fallback 到其他包——它根本不会参与全局查找。
为什么配了仓库却 still from packagist.org?
最常见原因是没禁用默认源,或者私有源本身没正确生成 packages.json。Composer 2.x 默认把 packagist.org 当作隐式兜底源,只要它没被显式关掉,就会永远在最后起作用。
- 运行
composer config --list查看当前生效的所有仓库(含全局 + 项目),确认{"packagist.org": false}是否存在、位置是否合理 - 用
composer update -vvv vendor/package观察日志:如果输出里压根没出现你配的私有源 URL,说明它连元数据都没去拉——大概率是 URL 拼错、HTTP 404 或 403,而 Composer 默认静默跳过 - 私有 Composer 源必须已公开
packages.json,且其中providers明确列出了你要覆盖的包名(如"laravel/framework"),否则即使 URL 正确,也会被跳过
CI 环境中务必用项目级 composer.json 声明
全局配置(~/.composer/config.json)在 CI 中不可控:不同 runner 可能有不同镜像设置,导致构建结果不一致。项目级配置才是唯一可靠方式。
- 用
composer config repositories.my-private composer https://pkg.example.com/添加源,它会写入项目composer.json的repositories数组末尾 - 但别依赖这条命令补全顺序——手动编辑
composer.json,确保私有源在前、镜像居中、{"packagist.org": false}在最后 - 删掉
vendor和composer.lock后再跑composer install:镜像只影响下载行为,不影响 lock 文件内容;如果 lock 里记的是 packagist.org 的 hash,换镜像也没用
真正容易被忽略的点是:私有源返回 403 或 500 时 Composer 默认不报错,只静默跳过——你以为配对了,其实它根本没连上。验证必须靠 -vvv 日志,而不是看 composer show 输出。











