symplify/monorepo-builder
Tools for managing PHP monorepos: scaffold a packages layout, merge and propagate composer.json data, validate shared dependency versions, bump inter-package constraints, and automate releases via a single monorepo-builder.php config.
Initialize the Monorepo
Run vendor/bin/monorepo-builder init once to scaffold a packages/ directory and a basic monorepo-builder.php config file.
Merge Package Dependencies
After adding packages to packages/, run vendor/bin/monorepo-builder merge to fold all composer.json sections (e.g., require, autoload) into the root composer.json.
Validate Shared Dependencies
Ensure consistency with vendor/bin/monorepo-builder validate.
Scenario: You have a new Laravel monorepo with 3 packages (auth, api, cli). After initializing:
composer require monorepo-php/monorepo --dev
vendor/bin/monorepo-builder init
Add packages to packages/ (e.g., packages/auth). Then merge:
vendor/bin/monorepo-builder merge
This aggregates all dependencies (e.g., laravel/framework) and autoload rules into the root composer.json.
Package Development
packages/auth).composer install in the root.Dependency Management
vendor/bin/monorepo-builder bump-interdependency "^1.0" to update mutual dependencies (e.g., auth and api both requiring shared-utils).vendor/bin/monorepo-builder validate.Release Automation
vendor/bin/monorepo-builder release v1.0 --dry-run.vendor/bin/monorepo-builder release v1.0.vendor/bin/monorepo-builder release patch.CI/CD Integration
merge and validate in CI to catch misconfigurations early.localize-composer-paths for testing packages in isolation:
vendor/bin/monorepo-builder localize-composer-paths
composer install --prefer-source
type: laravel-package in package composer.json and use disableAutoloadMerge for libraries:
$mbConfig->disableAutoloadMerge(
sections: [AutoloadSection::Autoload],
forTypes: [PackageType::Library]
);
autoload-dev to enable root-level testing:
$mbConfig->disableAutoloadMerge(
sections: [AutoloadSection::AutoloadDev],
forTypes: [] // Merge for all packages
);
dataToAppend to add root-level extra.publish:
$mbConfig->dataToAppend([
ComposerJsonSection::EXTRA => [
'publish' => [
'auth' => 'config/auth.php',
],
],
]);
vendor/bin/monorepo-builder localize-composer-paths
npm run dev --prefix packages/auth
vendor/bin/monorepo-builder merge
vendor/bin/pint
Autoload Merging Conflicts
autoload-dev merge breaks cross-package PHPUnit tests.AutoloadSection::AutoloadDev is merged for testable packages:
$mbConfig->disableAutoloadMerge(
sections: [AutoloadSection::Autoload],
forTypes: [PackageType::Library]
);
Package Replace Overrides
disablePackageReplace() may break symlinked dependencies in Laravel apps.$mbConfig->enablePackageReplace(); // Default behavior
Version Validation Failures
validate fails if packages use different versions of laravel/framework.bump-interdependency to align versions:
vendor/bin/monorepo-builder bump-interdependency "^10.0"
Dry-Run Ignored
--dry-run may not show all changes (e.g., replace section updates).monorepo-builder.php for disableDefaultWorkers() or custom workers.vendor/bin/monorepo-builder merge --dump-config
--verbose to release commands to see worker execution:
vendor/bin/monorepo-builder release v1.0 --verbose
packages/tests:
$mbConfig->packageDirectoriesExcludes([
__DIR__ . '/packages/tests',
]);
autoload before require):
$mbConfig->composerSectionOrder([
ComposerJsonSection::AUTOLOAD,
ComposerJsonSection::REQUIRE,
// ...
]);
$mbConfig->enableBranchAwareTagValidation();
Custom Workers
Implement ReleaseWorkerInterface for pre/post-release tasks (e.g., Slack notifications):
use Symplify\MonorepoBuilder\Release\ReleaseWorker\ReleaseWorkerInterface;
class SlackNotifyReleaseWorker implements ReleaseWorkerInterface {
public function work(Release $release): void {
// Send Slack message
}
}
Register in config:
$mbConfig->workers([SlackNotifyReleaseWorker::class]);
Decorators
Extend merge logic by decorating ComposerJsonMerger:
use Symplify\MonorepoBuilder\Merge\ComposerJsonMerger;
class CustomComposerJsonMerger extends ComposerJsonMerger {
protected function mergeAutoload(array $rootAutoload, array $packageAutoload): array {
// Custom logic
return parent::mergeAutoload($rootAutoload, $packageAutoload);
}
}
Bind in service container (e.g., Laravel’s AppServiceProvider).
Event Listeners
Listen to monorepo-builder.events (e.g., for Git hooks):
use Symplify\MonorepoBuilder\Event\MonorepoBuilderEvent;
event(new MonorepoBuilderEvent('merge.started'));
How can I help you explore Laravel packages today?