dex / composer-plug-and-play
Plug and play packages for Composer
Package info
github.com/edersoares/composer-plug-and-play
Type:composer-plugin
pkg:composer/dex/composer-plug-and-play
Requires
- php: ^8.3
- composer-plugin-api: ^2.3
- ext-json: *
Requires (Dev)
- composer/composer: ^2.3.0
- laravel/pint: ^1.7
- pestphp/pest: ^4
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- 0.28.0
- 0.27.0
- 0.26.0
- 0.25.0
- 0.24.0
- 0.23.0
- 0.22.0
- 0.21.0
- 0.20.0
- 0.19.0
- 0.18.0
- 0.17.0
- 0.16.0
- 0.15.0
- 0.14.0
- 0.13.x-dev
- 0.13.1
- 0.13.0
- 0.12.0
- 0.11.0
- 0.10.0
- 0.9.0
- 0.8.0
- 0.7.0
- 0.6.0
- 0.5.0
- 0.4.0
- 0.3.0
- 0.2.0
- 0.1.0
- dev-manifest-docs-review
- dev-manifest-review
- dev-manifest-docs
- dev-reset-manifest
- dev-manifest
- dev-lockfile
- dev-directories
- dev-autoload
- dev-new-approach
This package is auto-updated.
Last update: 2026-09-30 19:05:26 UTC
README
Composer Plug and Play lets you develop local packages inside a project without modifying composer.json. Keep your
working packages in packages/, run composer plug-and-play, and get a fully resolved Composer environment — without
polluting your real lock file.
Table of Contents
- Why?
- Requirements
- Installation
- Quick Start
- Directories and Files
- Commands
- Configuration
- The Manifest File
- Contributing
- License
Why?
Working with local packages via path repositories in composer.json pollutes the project's composer.json and
composer.lock with development-only entries that must not be committed.
Composer Plug and Play keeps this configuration isolated in packages/composer.json and packages/plug-and-play.lock,
so your real composer.json stays clean.
Requirements
- PHP 8.3 or higher
- Composer 2.3.0 or higher
Installation
composer require dex/composer-plug-and-play
Global installation
You can install Composer Plug and Play globally to use its abilities in all your local projects.
composer global require dex/composer-plug-and-play
Quick Start
-
Initialize the plug-and-play structure in your project:
composer plug-and-play:init
-
Clone or create a package inside
packages/:git clone git@github.com:your-org/your-package.git packages/your-org/your-package
-
Run plug-and-play to resolve everything:
composer plug-and-play
Your package is now available as if installed via Composer, without touching composer.json.
Directories and Files
Composer Plug and Play plugin needs a packages folder in
the project root directory where the plug and play structure will live.
packages/ ← managed by plug-and-play
├── <vendor>/<package>/ ← your local package (cloned or created)
│ ├── composer.json
│ └── ...
├── composer.json ← your plug-and-play configuration
├── plug-and-play.json ← generated merged config (do not commit)
└── plug-and-play.lock ← generated lock file (do not commit)
composer.json ← your real project config (unchanged)
composer.lock ← your real lock file (unchanged)
vendor/ ← standard Composer vendor directory
Commands
All commands use the plug-and-play.json and plug-and-play.lock files as source to project dependencies instead of
composer.json and composer.lock original files.
You can use composer pp and composer pp:* as alias for all commands.
| Command | Description |
|---|---|
plug-and-play |
Installs plug and play dependencies together with project dependencies |
plug-and-play:add |
Require a package into packages/composer.json |
plug-and-play:dump |
Same as composer dump-autoload, but using plug-and-play files |
plug-and-play:init |
Initialize plug and play plugin |
plug-and-play:install |
Same as composer install, but using plug-and-play files |
plug-and-play:reset |
Remove plug-and-play files |
plug-and-play:run |
Same as composer run-script, but using plug-and-play files |
plug-and-play:update |
Same as composer update, but using plug-and-play files |
Configuration
You can add additional configuration in packages/composer.json under the extra.composer-plug-and-play key.
Ignore plugged packages
Sometimes you may need to ignore a package that is under development:
{
"extra": {
"composer-plug-and-play": {
"ignore": [
"vendor-name/package-to-ignore"
]
}
}
}
Require dev dependencies from plugged packages
When developing a package or library you may need to require its dev dependencies:
{
"extra": {
"composer-plug-and-play": {
"require-dev": [
"vendor-name/package-to-require-dev"
]
}
}
}
Autoload dev dependencies from plugged packages
When developing a package or library you may need to autoload its dev dependencies:
{
"extra": {
"composer-plug-and-play": {
"autoload-dev": [
"vendor-name/package-to-autoload-dev"
]
}
}
}
The Manifest File
Every install, update and autoload dump writes packages/plug-and-play.php, a plain PHP file your application can
require to find out which packages are only there because of plug and play.
<?php return [ 'plugged' => ['acme/blog'], 'ignored' => ['acme/draft'], 'installed' => ['acme/blog', 'league/commonmark'], ];
plugged— the packages found underpackages/<vendor>/<package>.ignored— the plugged packages listed inextra.composer-plug-and-play.ignore.installed—pluggedplus every dependency they dragged in, computed as the difference betweenpackages/plug-and-play.lockand your realcomposer.lock. This is the list you want: it is what would disappear fromvendorif you ranplug-and-play:reset.
plug-and-play:reset deletes the file, so its absence simply means nothing is plugged.
Running a Laravel test suite as if nothing were plugged
A plugged package's service provider is auto-discovered, so it registers routes, config, observers and migrations
into the host application — which can break the host's own test suite. installed lets you switch that off at
runtime, without uninstalling anything.
Filter Laravel's PackageManifest, which is what feeds both providers() and aliases():
namespace App\Support; use Illuminate\Foundation\PackageManifest; class UnpluggedPackageManifest extends PackageManifest { protected function getManifest() { $file = $this->basePath . '/packages/plug-and-play.php'; $plugged = is_file($file) ? (require $file)['installed'] ?? [] : []; return array_diff_key(parent::getManifest(), array_flip($plugged)); } }
Then bind it in bootstrap/app.php when a flag asks for it, and set that flag in phpunit.xml:
$app->beforeBootstrapping(Illuminate\Foundation\Bootstrap\RegisterProviders::class, function ($app) { if (env('PLUG_AND_PLAY', true)) { return; } $app->singleton(PackageManifest::class, fn () => new UnpluggedPackageManifest( new Illuminate\Filesystem\Filesystem, $app->basePath(), $app->getCachedPackagesPath() )); });
Because the packages' service providers are never registered, their loadMigrationsFrom() calls never run either —
so php artisan migrate stops seeing their migrations too.
Contributing
Contributions are welcome. Please open an issue before submitting a pull request so the change can be discussed first.
composer test # run all tests composer format # format code with Laravel Pint (PSR-12)
License
Composer Plug and Play is licensed under the MIT license. See the license file for more details.