prefer-stable 是排序偏好而非开关,仅在多个版本满足约束时优先选 stable 版;必须置于 composer.json 根级,配合 minimum-stability 使用才有效。

prefer-stable 不是开关,而是“排序偏好”
prefer-stable 的作用非常具体:当多个版本都满足你的版本约束(比如 "^3.0")时,它让 Composer 在其中**优先挑 stable 版本**,比如 3.2.1 而不是 3.3.0-beta.2 或 dev-main。它不禁止非稳定版,也不改变你能装什么——那由 minimum-stability 控制。
- 如果你的
require里写了"monolog/monolog": "dev-main",prefer-stable: true完全无效,Composer 照装 - 如果
composer.lock已锁死一个dev-xxx版本,只运行composer install不会重选,prefer-stable压根不触发 - 它只在
composer update(或首次install解析依赖时)起作用,且仅影响「同一约束下多个候选」的排序
怎么配才真正生效?必须写对位置
prefer-stable 必须放在 composer.json 的**根对象**里,不是 config 下的子项。写错位置等于没写。
{
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
"symfony/console": "^6.4"
}
}
- ❌ 错误写法:
"config": { "prefer-stable": true }—— 这个配置被忽略 - ✅ 正确写法:顶层级直接写
"prefer-stable": true - 命令行临时启用:
composer update --prefer-stable,只对本次生效,适合 CI 流水线加固 - 全局配置
composer config -g prefer-stable true无效 —— Composer 不支持全局prefer-stable
为什么开了 prefer-stable 还装了 dev 包?三个高频原因
看到 dev-main 出现在 vendor 里,别急着怀疑配置,先查这三处:
- 你的
require或某个依赖的composer.json显式写了"some/pkg": "dev-main"或"@dev"—— stability-flags 优先级最高,直接覆盖prefer-stable - 上游包自身设了
"minimum-stability": "dev",又没声明"prefer-stable": true,它的子依赖就可能把dev带进来 - 你只运行了
composer install,而composer.lock里原本就锁着一个dev版本 —— 想让它重新评估,得加--with-dependencies或删 lock 后再 update
prefer-stable 和 minimum-stability 怎么搭才不打架?
minimum-stability 是门槛,prefer-stable 是偏好。两者配合才有意义:
-
"minimum-stability": "stable"+"prefer-stable": true→ 实际无差别,因为 stable 已是底线 -
"minimum-stability": "dev"+"prefer-stable": true→ 真正推荐组合:允许灵活引入开发版,但默认保稳;关键包如laravel/framework自动落到10.42.0而非11.x-dev - 想强制某包只用稳定版?用
"package/name": "^2.0@stable",比改全局配置更精准、更可控
最容易被忽略的是:这个偏好只在「有得选」时才起效。一旦依赖树里只有 dev 能解出来,prefer-stable 就只是安静看着它装上去。










