私有源必须置顶、packagist.org须显式禁用且置于末尾、type字段必须正确;Composer按repositories数组顺序硬性短路匹配,首个返回200+可解析JSON的源即锁定使用,后续全跳过。

私有源必须放在repositories数组最前面
Composer 不会“比较”多个源谁更优先,它只从 repositories 数组第一个元素开始发请求,只要该源对目标包返回 HTTP 200 + 可解析的 JSON(哪怕内容为空),就立刻锁定使用,后面所有源全跳过。这不是 fallback,是硬性短路。
常见错误是把私有源写在阿里云镜像之后、或者和 packagist.org 混在一起,结果 composer require myorg/utils 总是装到 packagist 上同名但不相关的包——不是网络慢导致的“偶尔错”,而是私有源根本没被查。
- 运行
composer config repositories确认当前真实顺序,别信注释或记忆 - 私有
type: "composer"源(如 Satis、Private Packagist)必须是数组第一项 -
type: "vcs"源(Git 地址)不参与元数据合并,只对显式require生效,不能抢基础包(如laravel/framework)的下载权
必须显式禁用 packagist.org,且写法要严格
默认情况下,Composer 会把 https://repo.packagist.org 当作隐式兜底源。哪怕你把私有源放第一位,只要它对某个包返回 404(比如还没发布),Composer 就立刻切回官方源,看起来像“优先级失效”。
禁用方式只有一种:在 repositories 数组**末尾**添加一个独立对象 {"packagist.org": false}。
- 键名必须精确为
packagist.org(少一个点、多一个空格、拼成packagist.com都无效) - 必须是数组里的单独一项,不能嵌套进其他仓库配置里
- 不能写成
"packagist": false或"disable-packagist": true,会被静默忽略 - 验证是否生效:运行
composer config repositories,输出中不应出现https://repo.packagist.org
type 字段决定行为,混用等于配置失效
Composer 根据 type 决定怎么用这个仓库,不是“通用源”。写错 type,整条配置就等于不存在。
-
type: "composer":用于私有 Packagist 类服务(Satis、Private Packagist),支持全局元数据匹配 -
type: "vcs":仅响应显式require vendor/name,URL 必须是合法 Git 地址(如https://gitlab.example.com/myorg/utils.git),且目标仓库根目录要有composer.json,其中name必须与require中完全一致 -
type: "package":手动声明单个包的元数据,适合不想暴露 Git 地址的场景,但需手写完整版本信息 - 写成
type: "git"、type: "github"或漏掉type,配置直接被跳过
本地路径包要用 type: "path",且路径必须相对
想让 Composer 直接链接本地目录?不能用 vcs,得用 type: "path",它的匹配逻辑和优先级规则完全不同。
-
url必须以./或../开头,如"url": "../my-package"✅;"url": "/home/user/pkg"❌(绝对路径静默失败) - 本地包的
composer.json中name必须和require中逐字一致,大小写、斜杠方向都不能错 - 启用符号链接需加
"symlink": true,否则默认复制;Windows 下 junction 创建失败时不会报错,只会静默 fallback 到 copy - 验证是否真生效:加
-vvv运行composer require myorg/utils,日志中应出现Symlinking from ../my-package
真正起作用的只有三件事:私有源置顶、packagist.org 显式关掉、type 写对。其余任何“权重”“fallback”“自动切换”都是误解。每次改完都要删掉 vendor 和 composer.lock,再跑一次 composer install,否则旧 lock 文件会继续走原来的源。











