devkit / composer-link
Link local Composer packages via path repositories. Composer plugin: `composer link`, `composer add`, `link-help`, `local-bootstrap`, `local-install`, and related commands.
Package info
github.com/stuarttodd-dev/devkit-composer-link
Type:composer-plugin
pkg:composer/devkit/composer-link
Fund package maintenance!
Requires
- php: ^8.3
- composer-plugin-api: ^2.2
- composer/semver: ^3.4
- symfony/console: ^6.4|^7.0
- symfony/filesystem: ^6.4|^7.0
- symfony/process: ^6.4|^7.0
Requires (Dev)
- composer/composer: ^2.7
- pestphp/pest: ^3.0
- phpmd/phpmd: ^2.15
- phpstan/phpstan: ^1.12
- rector/rector: ^1.2
- squizlabs/php_codesniffer: ^3.10
README
Composer Link
Local package path overrides for Composer.
devkit-composer-link
Local path overrides for Composer dependencies, with a separate local manifest so your committed composer.json and composer.lock stay clean.
Package: devkit/composer-link
Why this exists
When you need to test package changes inside a real app, the usual workflow often requires:
- hand-edit root
composer.jsonrepositories - point dependencies at local folders
- remember to undo everything before committing
Composer Link stores local override state in dedicated local files, rebuilds managed path repositories, and keeps your team baseline untouched.
Prerequisites
- PHP 8.3+
- Composer 2.2+ (plugin allow-list support)
Install
Install in the consuming application (not in the library repo you are editing):
composer require --dev devkit/composer-link
Allow the plugin (Composer 2.2+)
Approve the interactive prompt, or add this explicitly:
{
"config": {
"allow-plugins": {
"devkit/composer-link": true
}
}
}
Run from project root
All commands should run from your application root (where the committed composer.json lives).
Use:
composer link-help
If the package is installed correctly, composer list will include:
link, add, unlink, promote, linked, refresh, link-doctor, local-bootstrap, local-install, link-help.
At a glance
| Command | In one sentence |
|---|---|
link |
Override an existing dependency to a local path. |
add |
Bootstrap a dependency from local path before it exists in committed manifest/registry. |
unlink |
Remove local override state and restore or remove requirement. |
promote |
Move a locally-managed package back to a published constraint. |
linked |
Show all packages currently managed by Composer Link. |
refresh |
Rebuild managed path repositories in local manifest from state file. |
link-doctor |
Verify local setup and ensure ignore rules/local files are correct. |
local-bootstrap |
Copy committed manifest/lock into local manifest/lock files. |
local-install |
Install using local manifest (COMPOSER=composer.local.json). |
link-help |
Print a concise command/arguments/options overview in terminal. |
Configuration
Composer Link reads optional config from root composer.json under extra.composer-link.
{
"extra": {
"composer-link": {
"overrides_file": "packages-local.json",
"local_composer_json": "composer.local.json"
}
}
}
| Key | Role |
|---|---|
overrides_file |
Local state file with managed packages, paths, mode, constraints. |
local_composer_json |
Local Composer manifest used for path repositories and local update/install runs. |
Files and folders
Default local artifacts:
packages-local.json: plugin state (gitignore this).composer.local.json: local manifest (gitignore this).composer.local.lock: lockfile for local manifest (gitignore this).
Committed baseline files stay canonical:
composer.jsoncomposer.lock
Legacy note: composer.local-packages.json is read only as fallback when packages-local.json is missing/empty; next write persists to packages-local.json.
Command reference
Use composer help <command> for full option docs.
link — override existing dependency
composer link <package> <path>
Examples:
composer link my-vendor/my-package ../packages/my-package composer link my-vendor/my-package ../packages/my-package --constraint=@dev composer link my-vendor/my-package ../packages/my-package --no-update composer link my-vendor/my-package ../packages/my-package --no-symlink
add — bootstrap new local dependency
composer add <package> <path>
Examples:
composer add my-vendor/new-lib ./libs/new-lib composer add my-vendor/new-lib ./libs/new-lib --no-dev composer add my-vendor/new-lib ./libs/new-lib --constraint=^0.1
unlink — stop managing a package locally
composer unlink <package>
If package was added via add, use --remove to remove requirement:
composer unlink my-vendor/experimental-package --remove
Useful flags:
--no-update--remove(required for bootstrap-mode removals)
promote — move to published constraint
composer promote <package> <constraint>
Examples:
composer promote my-vendor/my-package ^1.5
composer promote my-vendor/my-package ~2.3.0
composer promote my-vendor/my-package ^1.0 --no-update
linked — show managed packages
composer linked
Outputs package, mode (override/bootstrap), path, symlink behavior, constraint, and path status.
refresh — rebuild managed path repos
composer refresh composer refresh --no-update
link-doctor — validate setup
composer link-doctor
Checks:
- local ignore block/files
- linked path existence
- count of plugin-managed path repositories in local manifest
local-bootstrap — create local manifest files
composer local-bootstrap composer local-bootstrap --force
Copies committed composer.json (+ composer.lock if present) to local equivalents.
local-install — install via local manifest
composer local-install
Equivalent to:
COMPOSER=composer.local.json composer install
Examples:
composer local-install --no-dev composer local-install --prefer-dist composer local-install --no-scripts
link-help — command summary in terminal
composer link-help
composer help link-help
Typical workflows
Override a released package with local checkout
composer link your-vendor/your-package ../packages/your-package
If local branch/version does not satisfy baseline constraint:
composer link your-vendor/your-package ../packages/your-package --constraint=@dev
Bootstrap package before Packagist
composer add your-vendor/new-package ../packages/new-package
Later switch to published dependency:
composer promote your-vendor/new-package ^1.0
Version control and safety
Keep shared baseline committed:
composer.jsoncomposer.lock
Keep local override artifacts out of Git:
packages-local.jsoncomposer.local.jsoncomposer.local.lock
packages-local.json is Composer Link state only; Composer itself reads whichever manifest COMPOSER points to.
For local workflows:
composer local-bootstrap composer link vendor/package ../path/to/package composer local-install
Before merging release work, align committed manifest/lock with intended published constraints (via promote, unlink, or normal manifest edits).
Support
If this project saves you time and you want to support future updates:
License
MIT (see composer.json).