The upgrade guide is the compact incompatibility checklist. This guide provides the commands, configuration examples and operational detail for each required migration. Features that need no migration are described in the documentation and the changelog.
composer require php-forge/foxy:^0.4 --with-all-dependenciesFoxy 0.4 accepts symfony/console ^7.4 || ^8.0. Console 8 requires PHP 8.4, so a project on PHP 8.3 keeps 7.4;
--with-all-dependencies lets Composer move the shared Symfony packages when the project allows it.
Foxy no longer runs <manager> --version each time Composer loads the plugin. The manager is selected when an install,
an update, or composer foxy:audit needs it:
- Composer commands that need no manager (
about,show,validate, ...) run without probing one and never fail because a manager is missing or unsupported. - An unknown
managervalue, several recognized lockfiles, a lockfile whose manager is not installed, or no manager at all are reported by the first command that needs the manager;composer foxy:auditreports them with exit status2.
A CI job that relied on any Composer command failing early because of a missing manager must run composer install or
composer foxy:audit to keep that check.
composer foxy:auditsends the registry packages infoxy.lockto the registry's bulk advisories endpoint (POST /-/npm/v1/security/advisories/bulk). Localfile:packages are excluded, and a lock containing only local packages is clean without a registry request. When registry packages remain, a private registry must implement that endpoint (Verdaccio: enable itsauditmiddleware); otherwise the audit fails with status2. Independently,--no-devis rejected, as for Deno, because the native manager installs the development dependencies together with the others.- The install directory gains a hidden
.foxy-installed.jsonfile that records what Foxy installed. The first install after the upgrade extracts every registry package once and writes it; later installs keep the registry packages whose directory and recorded entry still matchfoxy.lock, copy thefile:packages again, and report only what changed, printingNothing to install, update or removewhen nothing did. Run Composer with-vto list the kept and refreshed packages and-vvto follow the registry traffic. Delete the file to extract every registry package again.
- The
package.jsonrestore that follows a failed dependency merge or manager run now happens before thefoxy.post-solveevent. Apost-solvelistener that throws no longer triggers it; only the Composer rollback runs. - The Composer rollback runs on a private event dispatcher: command and autoload events never reach the project's
scripts or other plugins. Package events (
pre-package-install,post-package-update, ...) are still dispatched by Composer's installation manager and do reach them, where 0.3 skipped them. A root script bound to a package event that must not run during a rollback has to guard itself.
The classes that custom managers, audit parsers, and CVE resolvers extend changed in this release. A project that
configures Foxy through composer.json is not affected. One change binds silently:
AbstractAssetManager::buildCommand() and buildUnconfiguredCommand() lost their first parameter, the default binary,
so a subclass that still passes it has the binary bound as the action. Drop that argument and return a custom binary
from getDefaultBinary().
Before updating, make sure the environment provides:
- PHP 8.3 or later. PHP 8.1 and 8.2 are not supported.
- Composer 2.10.2 or later.
- One supported frontend manager when Foxy runs it or audits with it: Bun
^1.4.0, Deno^2.9.7, npm>=10.9.8, pnpm^11.23.0, or Yarn^4.18.0. npm needs a Node.js version its release supports, pnpm needs Node.js>=22.13.0, and Yarn needs Node.js>=18.12.0on a release that still receives security updates.
Earlier manager versions are rejected. The manager-version setting can narrow the built-in constraint for a project
but cannot widen it. The Ctype and Mbstring extensions are no longer required.
composer config allow-plugins.php-forge/foxy true
composer require php-forge/foxy:^0.3 --with-all-dependenciesThe equivalent composer.json configuration is:
{
"require": {
"php-forge/foxy": "^0.3"
},
"config": {
"allow-plugins": {
"php-forge/foxy": true
}
}
}A library that keeps Foxy in require-dev updates that constraint to ^0.3 as well.
Foxy selects the manager from a single recognized lockfile or from an available executable. Several recognized lockfiles require an explicit choice. For predictable upgrades and CI runs, configure the manager and commit its lockfile:
{
"config": {
"foxy": {
"manager": "npm"
}
}
}Remove stale lockfiles of other managers before the first Composer operation with Foxy 0.3, then bring the manager to a supported version:
- npm:
npm --versionmust satisfy>=10.9.8; runnpm installand commit thepackage-lock.jsonchanges. npm 10.9.8 requires Node.js^18.17.0 || >=20.5.0; see the npm documentation for the release in use. - pnpm: pnpm 11 requires Node.js 22. Upgrade Node.js, then run
pnpm self-update 11,pnpx codemod run pnpm-v10-to-v11, andpnpm install;pnpm --versionmust satisfy^11.23.0. Review the codemod result with the pnpm migration guide and commitpnpm-lock.yamland the configuration changes. - Bun: run
bun upgrade;bun --versionmust satisfy^1.4.0. Foxy recognizes only the text lockfile, so convert a legacybun.lockbwithout changing the resolved versions withbun install --save-text-lockfile --frozen-lockfile --lockfile-only, commitbun.lock, and deletebun.lockb. A project that relied onyarn.lockfor Bun's automatic selection generatesbun.lockor setsmanagertobun. - Yarn: Yarn 1, 2, and 3 are not supported. Install Corepack (
npm install --global corepack,corepack enable), runyarn set version 4.xandyarn install;yarn --versionmust satisfy^4.18.0. Commit thepackageManagerfield,yarn.lock, and the Yarn configuration. The installation guide, the migration guide, and the Yarn 4 release notes document the configuration and command changes, including the move from.npmrcor.yarnrcto.yarnrc.yml.
Foxy copies into its local package representation only the metadata it needs to resolve dependencies and check
compatibility. Lifecycle scripts, devDependencies, executable definitions, entry points, and publishing metadata of
an installed Composer dependency are no longer propagated. A library moves its runtime requirements to dependencies,
optionalDependencies, or peerDependencies, ships prebuilt assets with the Composer package, or asks the consuming
application to declare its own build steps in package.json.
A root-package-json-dir of a library must resolve inside that library's installation directory; a value that leaves it
is rejected with a RuntimeException. Foxy regenerates the local file: references relative to the consuming
package.json: review a project with a custom root after the first update and commit the resulting manifest changes.
Foxy resets composer-asset-dir recursively and therefore checks that it owns the directory. Filesystem, project, and
vendor roots, directories containing either, and symbolic links are rejected. An existing, non-empty custom directory
must contain Foxy's .foxy-managed marker: before upgrading, verify that the directory holds only generated Foxy data,
empty it, and let the first Foxy 0.3 run recreate and mark it. A new or empty directory is marked automatically.
Both fallbacks stay enabled by default; a project that disabled one should confirm that keeping partial state after a manager error is still intended.
The asset rollback runs when package merging or the manager fails. The Composer rollback runs after every solve exception and every non-zero manager result. When the Composer restore succeeds, Foxy rethrows the original error; when it fails too, Foxy reports the rollback error with the original failure as its previous exception. The rollback does not run project scripts, and a non-zero result of the rollback installer is reported instead of being treated as a success.
The rollback snapshot of composer.lock and the vendor directory is taken at Composer's pre-operations-exec event.
The root composer.json is not part of it, and composer require or composer remove may already have changed it:
inspect and, when necessary, revert the root manifest after a failed operation.
enabled: false bypasses manager discovery, fallback snapshots, package merging, and manager execution.
run-asset-manager: false keeps package merging but skips manager probing, version validation, execution, and the npm
cleanup of node_modules/@composer-asset/*. composer foxy:audit still validates and invokes the selected manager in
that mode; it never installs, updates, or repairs dependencies.