Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Monorepo Builder Laravel Package

symplify/monorepo-builder

Toolkit for managing PHP monorepos: merge package composer.json files into the root, validate dependency versions, bump interdependencies, propagate versions back, manage package aliases, and automate releases. Configured via monorepo-builder.php; requires PHP 8.2+.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Framework-agnostic Composer tooling, not a Laravel package: there is no service provider, no publishable config, no Artisan commands, no facade. Everything runs as vendor/bin/monorepo-builder from the repo root against a monorepo-builder.php config file. For a Laravel shop this is a neutral-to-positive on architecture: zero coupling to the framework means the tool survives Laravel major upgrades, but it also means all Laravel-specific wiring (composer scripts, CI jobs, release approvals) is glue we own.
  • Value proposition maps cleanly to a common Laravel org shape: one repo containing packages/* (shared domain libraries, internal SDKs, Blade/UI packages) plus one or more Laravel type: project apps. The commands that matter to us are merge (single root composer.json so root-level PHPUnit/PHPStan/Pint can resolve every namespace), validate (kill shared-dependency version drift across packages), and release (deterministic tag + next-dev bump).
  • It is a dev-only dependency. Nothing ships to production, no runtime footprint, no autoload surface in deployed artifacts. That dramatically caps the blast radius: worst case is broken local/CI tooling, not a broken app.
  • MIT license — clean for commercial use, no attribution burden in distributed artifacts.

Integration feasibility

  • Low effort to try, moderate effort to do correctly. Install is one composer require --dev, and validate is usable immediately in read-only mode with no config beyond package discovery. The complexity is concentrated in two configuration areas that are genuinely subtle:
    • Autoload merge semantics. Composer treats autoload-dev as root-only; path-repo dependencies never register their dev autoload. So if we skip AutoloadDev folding, root-level PHPUnit silently stops discovering library test classes. This is a config decision with a non-obvious CI failure signature.
    • The replace section. Default behavior writes replace entries at self.version for every internal package, which short-circuits Composer's symlink install for path-repo consumers. Laravel apps that require internal libraries via path repos are exactly the case that breaks. disablePackageReplace() + selective disableAutoloadMerge() is the documented escape hatch, but it is a decision a TPM should make before rollout, not during an incident.
  • Release automation (release) mutates git state — bumps interdependencies, tags, pushes tags, pushes next dev versions. That is a governance decision as much as a technical one; it must be gated behind protected-branch policy and ideally manual approval.
  • No Laravel version gate from the tool itself, but PHP 8.2+ is required. That aligns with Laravel 11/12 and excludes Laravel 9/10 stacks still on PHP 8.0/8.1 (legacy ^11.2 supports 8.1 but is explicitly unmaintained).

Technical risk

  • Supply-chain / package identity risk (highest). The README instructs composer require monorepo-php/monorepo --dev while the package under evaluation is symplify/monorepo-builder. A rename or namespace migration in flight is a real risk: we could be pinning a package whose canonical name, Packagist vendor ownership, and future release channel are ambiguous. Must be verified before the first install.
  • Maintenance concentration. ~529 stars, 0 reported dependents, single-vendor origin (Symplify). That is a small ecosystem with thin external validation. Not disqualifying for dev tooling, but it means we should assume we may need to fork or replace it within 12–24 months.
  • Metadata anomaly. "Last release: 2026-07-31" is a future date relative to normal operation — either a data artifact or an unusual release flow. Treat release-cadence signals as unverified and confirm against Packagist/CHANGELOG directly.
  • Destructive-by-design commands. merge rewrites the root composer.json; release pushes tags. Both are high-consequence if invoked ad hoc by a developer rather than through a pipeline.
  • Silent drift risk. If validate is not a CI gate, version drift across packages returns within weeks and the tool's main benefit evaporates.

Key questions

  1. Which package name is canonical for new installs — symplify/monorepo-builder or monorepo-php/monorepo — and who controls the Packagist vendor?
  2. Do we actually have (or plan) multiple packages in one repo, and do we publish splits to Packagist, or are these internal-only? This determines whether replace, package-alias, propagate, and localize-composer-paths are in scope at all.
  3. Do our Laravel apps consume internal libs via path repos + symlinks? If yes, disablePackageReplace() is mandatory from day one.
  4. Is anyone on the team willing to own the monorepo-builder.php config as a first-class artifact (review, test, document)?
  5. Does automated tag-and-push conflict with our branch protection, signed-tag, or changelog policy?
  6. What is our exit ramp if the package is abandoned — plain Composer scripts + a small custom PHP script, or a fork?

Integration Approach

Stack fit

  • Adopt as a root-only dev dependency, pinned to an exact version, committed alongside the lockfile. It belongs in the same tier as PHPStan, Pint, and Rector — not in any package's own composer.json.
  • Expose it through Composer scripts ("monorepo:validate", "monorepo:merge") so nobody invokes the binary with ad hoc flags, and so the commands are discoverable and greppable.
  • Ignore any temptation to wrap it in Artisan commands. The value is the CI contract, not developer ergonomics.

Migration path

  • Do not migrate onto it. Run it alongside existing tooling until it proves itself. Concretely: start with validate only, in report-only mode, for two sprint cycles. It makes no writes and surfaces exactly the drift problem it exists to solve, which gives you a data-backed adoption case.
  • Phase 2 introduces merge on a throwaway branch, with the generated root composer.json diff reviewed in a PR and the pre-existing file kept as the fallback for one release cycle.
  • Phase 3 introduces release in --dry-run inside CI, comparing predicted output against what the release manager actually did manually.
  • Only then hand the release pipeline over to the tool.

Compatibility

  • Enforce a PHP floor of 8.2 in the monorepo root (config.platform.php) so local and CI behavior match; this also aligns with Laravel 11/12.
  • Verify Composer 2.x compatibility explicitly and pin Composer's major in CI images.
  • Run a spike against a representative branch that includes at least one type: project Laravel app and one type: library package with tests, so both autoload branches and the replace/path-repo interaction are exercised before any commitment.
  • Set type explicitly in every internal package's composer.json. The type filter in disableAutoloadMerge() matches literally and does not apply Composer's "missing type defaults to library" rule — untyped packages will silently slip through.

Sequencing

  1. Verify identity (½ day): confirm Packagist vendor, CHANGELOG, maintainer activity, and the correct install name. Block everything else on this.
  2. Read-only pilot (1 day): validate in CI as a non-blocking job; baseline the drift count.
  3. Config decisions (1 day): decide replace on/off, autoload skip matrix, package discovery paths, section ordering. Document the decisions and the rationale in the repo.
  4. Gate enforcement (1 day): promote validate to blocking; add merge to a scheduled/PR job with diff review.
  5. Release automation (2–3 days): dry-run first, then a manually-approved pipeline with a documented rollback (delete tag, revert next-dev commit).
  6. Split-publishing tooling (deferred): only if we publish packages externally — propagate, package-alias, localize-composer-paths, LTS branch-aware validation.

Operational Impact

Maintenance

  • Ongoing cost is small but non-zero: the monorepo-builder.php file is a living artifact that must be reviewed whenever a package is added, a type changes, or the autoload strategy shifts. Budget roughly one named owner and a few hours per release cycle.
  • Version pinning is the main lever. Pin exactly, upgrade deliberately, and read the CHANGELOG for MBConfig API changes — the README already shows one migration (the zero-argument disableAutoloadMerge() deprecation), which is a signal that config APIs are still moving.
  • Deprecation notices (E_USER_DEPRECATED) should be treated as hard CI failures so config rot surfaces immediately rather than at the next upgrade.

Support

  • No commercial support, no SLA, MIT + community issue tracker. Internal ownership is therefore mandatory, not optional. Designate a "build tooling" owner in the platform team.
  • Because adoption is thin (0 dependents), expect to be early on edge cases. Maintain an internal runbook covering: how to interpret a merge diff, how to resolve autoload-dev discovery failures, and how to unwind a partial release.
  • Have a documented exit ramp (Composer scripts + ~150 lines of custom PHP) scoped in advance so abandonment is an inconvenience, not a project.

Scaling

  • Scales well along the axis that matters: package count. merge and validate are linear and cheap; CI time grows with the number of packages, not with the tool.
  • Does not solve repo size, Composer install time, or CI parallelism — those remain our problems. If the monorepo grows past a few dozen packages, expect to invest separately in Composer caching and path-repo pruning.
  • The release pipeline scales by adding workers, which is a clean extension point (ReleaseWorkerInterface) — good sign for long-term fit if our release process becomes more elaborate.

Failure modes

  • Premature tag push. release succeeds at TagVersionReleaseWorker and fails at PushNextDevReleaseWorker → tag exists, dev branch doesn't. Recovery: manual next-dev bump. Mitigation: --dry-run in CI plus manual approval, and worker ordering reviewed by the release owner.
  • Silent stale dependencies. replace enabled alongside path repos → apps never pick up library changes; local builds pass against cached code. Mitigation: disablePackageReplace() if we use path repos at all.
  • Red CI from autoload-dev skip. Cross-package PHPUnit discovery breaks with a confusing "class not found" that looks like a namespace typo. Mitigation: don't skip AutoloadDev unless we have an alternative discovery mechanism; if we must, document it prominently.
  • Root composer.json churn. merge rewrites a file many people edit by hand. Mitigation: treat root composer.json as generated, commit diffs through PR review, and forbid manual edits in the contributing guide.
  • Abandonment. New PHP minor arrives, package lags, we're blocked. Mitigation: pinned version, exit ramp, and a quarterly check on release activity.

Ramp-up

  • Senior developer with Composer depth: ~2–4 hours to productive use on validate; 1–2 days to confidently own the autoload/replace configuration.
  • Rest of the team: near-zero — they interact only through CI output and the release job.
  • Release manager: half a day of paired dry-runs before the first live automated release.
  • Overall recommendation: adopt, but conditionally and in stages — confirm package identity first, start read-only, and treat the replace/autoload configuration as a design decision with a written record rather than a config file someone tweaks. The framework-agnostic, dev-only nature makes the downside bounded; the thin ecosystem and ambiguous package naming make verification the gating step.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
muka/shape-reader
tdt/json
refinery29/php-cs-fixer-config
hotmeteor/eco-env
mvaliolahi/hydrate
wearede/tbcpay-php
parsnick/steak
thibaud-dauce/mattermost-php
multilinguals/apollo-client
antaresbr/collection
kr0lik/phpstan-rules
loco/loco
starfederation/datastar-php
yupmin/modern-phystrix
stephenjude/extended-artisan-commands
lumphp/laravel-macroable
lumphp/laravel-collections
lumphp/laravel-contracts
sermepa/sermepa
arkecosystem/fortify