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

Package Versions Laravel Package

ocramius/package-versions

PackageVersions gives PHP applications fast, zero-I/O access to the installed versions of Composer dependencies. Version data is compiled from composer.lock at install time, so \PackageVersions\Versions::getVersion() returns a package's version and commit hash without any runtime disk reads—ideal fo...

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Single-purpose, low-footprint utility: one static class (PackageVersions\Versions) exposing getVersion(string $package): string, returning 1.2.3@<commit-ref>. No service provider, no config file, no facade, no container bindings, no migrations — it sits alongside Laravel rather than inside it.
  • Since 2.0.0 the package is a library, not a Composer plugin. The 1.x design generated a PHP class during composer install/update; 2.x delegates to Composer 2's own composer-runtime-api (Composer\InstalledVersions). That removes the install-time file mutation and the class of bugs that came with it (--no-scripts, --classmap-authoritative, vboxfs, composer remove, lock: false).
  • This is the central architectural finding: on any Composer 2 project — which Laravel 8+ universally is — the package is a thin shim over a dependency you already have. The functional delta over calling Composer\InstalledVersions::getPrettyVersion() directly is the version@ref string format and an OutOfBoundsException on unknown packages. A TPM should treat this as a convenience wrapper, not infrastructure.
  • Legitimate fit points inside a Laravel app are narrow and cross-cutting: release/version metadata in health and readiness endpoints, Sentry/exception-reporter release tagging, deployment-verification and cache-busting keys, and diagnostic output in artisan commands or bug-report bundles. It is not a service-layer, domain, or data-access dependency.

Integration feasibility

  • Install is composer require ocramius/package-versions and nothing else. Expected effort for the adoption itself: well under a day, including tests. The surrounding decisions (what consumes the version string, and whether to abstract it) dominate the cost.
  • No Laravel package discovery registration is required or provided. No published config. Nothing to boot.
  • README recommends config.optimize-autoloader: true (or composer dump-autoload --optimize) to avoid autoload I/O on first access. Most Laravel production images already do this; verify rather than assume, because it is the only tuning knob that exists.
  • Commercial support is available via Tidelift, with direct maintainer contact ([email protected]) advertised for private projects — relevant if procurement requires a support path for third-party code.

Technical risk

  • PHP floor is the primary risk. The 2.12.0 release notes explicitly drop PHP 8.2 and 8.3 support, and 2.11.0 added 8.5. A package that requires PHP ≥ 8.4 cannot be installed on the majority of current Laravel estates (Laravel 11/12 support 8.2+). Any team on 8.1–8.3 must pin to an older minor (2.10.x or earlier) or skip the package. This must be resolved against the actual PHP matrix before anything else is evaluated.
  • Maintenance signal is thin in a specific way. The changelog for 2.8–2.12 is almost entirely Renovate bot PRs, dependency bumps, and CI action updates; issues resolved per release are consistently zero. That is not abandonment, but it is a low-touch, effectively single-maintainer project (Ocramius, with historical contributions from Jean85). Bus factor is 1, mitigated only by commercial support and by the fact that the code is a few dozen lines.
  • Redundancy risk / opportunity cost. The internal opportunity score (33.35) and overall score (38.6) reflect that this is a solved problem in the platform. Adding it introduces a dependency whose behaviour is dictated by Composer's generated InstalledVersions payload anyway.
  • Metric hygiene. Dependents: 0 is inconsistent with 3.1k stars and heavy historical Packagist download volume; treat that field as unreliable for this package and do not use it in a build-vs-adopt argument.
  • BC surface is small but real. 2.0.0 removed the Versions::ROOT_PACKAGE_NAME constant in favour of rootPackageName(). Any tutorial, Stack Overflow snippet, or legacy snippet copied from 1.x-era content will break, which is a documentation and code-review risk more than a runtime one.

Key questions

  1. Which PHP versions are actually in the fleet's support matrix, and does the resolved package version install on all of them? If any app is on 8.2/8.3, the answer likely changes the recommendation to "use Composer\InstalledVersions directly."
  2. What is the concrete consumer? Name the endpoint, header, or log field that needs this. If we cannot name it, we do not need the package.
  3. Does the team accept a single-maintainer, Tidelift-backed dependency for something Composer provides natively? If not, standardise on Composer\InstalledVersions and avoid the shim entirely.
  4. Does the deployment pipeline run composer install at image build time with a lock file present, and does it reset OPcache / reload PHP-FPM after deploy? Both preconditions matter for correctness rather than for this package specifically.
  5. Is --no-dev used in production, and will any code path query a dev-only package name?

Integration Approach

Stack fit

  • Fits the Laravel/PHP stack at the "ambient runtime metadata" layer, not the application layer. Correct placement is a single small wrapper — e.g. app/Support/AppVersion.php or a ReleaseInfo value object — bound as a singleton, with PackageVersions\Versions (or Composer\InstalledVersions) called only inside it.
  • Nothing in controllers, jobs, models, or service providers outside the wrapper should reference PackageVersions\*. This keeps the exit cost of removing the dependency at roughly one file, which matters given the redundancy noted above.
  • Natural, low-risk consumers: a /health or /version JSON response, an exception-reporter release field, a cache-key salt for asset/route caches, and a php artisan about-style diagnostic line.

Migration path

  • Greenfield adoption on an existing Laravel app: composer require, add the wrapper, wire one consumer, add a feature/unit test asserting the wrapper returns a non-empty name@ref string for a known installed package and throws/returns null for an unknown one.
  • If migrating off direct PackageVersions\Versions calls (already-present transitive usage), invert the wrapper so it delegates to Composer\InstalledVersions::getPrettyVersion() plus getReference(), replicating the version@ref format. That is a mechanical change and eliminates the dependency outright.
  • If migrating legacy 1.x-era code, the two things to sweep for are the ROOT_PACKAGE_NAME constant and any assumption that a generated file exists in src/Packages/Versions.php (it does not in 2.x).

Compatibility

  • Requires Composer 2 (composer-runtime-api); Composer 1 has been EOL since 2020, so this is a non-issue in practice but should be confirmed for any legacy CI image still on Composer 1.
  • Requires PHP ≥ 8.4 on the current release line — pin explicitly in composer.json (e.g. "ocramius/package-versions": "^2.10") rather than allowing a floating ^2, otherwise a routine composer update on a PHP 8.2/8.3 app will fail resolution or force an unintended platform bump.
  • Coexists cleanly with --no-scripts, --classmap-authoritative, --no-dev, and read-only container filesystems, all of which were 1.x pain points. This is the single biggest compatibility improvement of 2.x and should be stated plainly in the ADR.
  • No conflict surface with Laravel's own versioning APIs (Application::VERSION), Debugbar, Telescope, or Sentry SDKs; consumers are reading, not registering.

Sequencing

  1. Constraint check (½ day): resolve the PHP matrix against the package's composer.json require for the intended version. Gate everything else on this.
  2. Consumer definition (½ day): name the endpoint/field, agree the output format (version@ref vs version), and agree the unknown-package behaviour.
  3. Wrapper + test (1 day): implement the abstraction, unit-test both the happy path and the missing-package path.
  4. Single consumer rollout (1 day): ship the health/version field or the Sentry release tag behind normal deployment; verify against a staging deploy.
  5. Pin + document (½ day): lock the version constraint, add the ADR note explaining why this exists and how to remove it.
  6. Deferred: any broader rollout (multiple consumers, dashboarding on the version field). Do not schedule before step 4 proves the value.

Operational Impact

Maintenance

  • Near-zero ongoing effort: no configuration to drift, no schema, no background processes, no scheduled commands. Upgrades are Renovate-style dependency bumps; the changelog shows the project itself ships releases that are almost exclusively dependency and CI updates, so the upgrade delta is usually empty.
  • The real maintenance burden is governance of the wrapper: keeping it the sole call site, and revisiting the decision if Composer's InstalledVersions API or the PHP floor changes.
  • Because the project is effectively single-maintainer, add a calendar reminder or dependency-bot watch on the repository rather than relying on organic discovery of a stall.

Support

  • Community support via GitHub issues, backed by an advertised Tidelift commercial option and a direct maintainer contact for private projects. No SLA without Tidelift.
  • The blast radius of an unsupported dependency here is small: if the package is abandoned, the wrapper swap to Composer\InstalledVersions is a one-file change with no data migration. This should be recorded as the explicit fallback in the ADR — it is the main reason the risk is acceptable at all.
  • Internal support load is minimal, but the wrapper should be documented so on-call engineers know where version strings come from when a health endpoint reports something unexpected.

Scaling

  • Effectively free at any scale. Version data is a static PHP array compiled into the autoloader; there is no I/O, no network call, no cache lookup, and no per-request allocation beyond a string. With optimize-autoloader enabled, access cost is a class-map hit.
  • No interaction with horizontal scaling, queue workers, or long-running Octane/Swoole processes — with one caveat: in a long-lived worker, the version string is fixed at process start. That is the desired behaviour for release tagging, but it means a zero-downtime deploy that reuses old workers will report the old version until the worker recycles. Verify worker restart behaviour matches expectations.

Failure modes

  • OutOfBoundsException when querying a package that is not installed in the current context — most commonly a dev-only dependency queried in a production image built with --no-dev. This is a configuration/consistency bug, not a package bug, but it will surface at runtime and must be handled in the wrapper (return null, log, never let it 500 a health endpoint).
  • Missing or stale composer.lock at build time, or a composer install run outside the image build, yields wrong or absent version data. The version reflects the lock file, not the actual deployed code — if the image is built from a different commit than the lock file implies, the reported version is misleading.
  • Stale OPcache after deploy: the version payload is baked into generated PHP at install time. If OPcache is not reset and PHP-FPM not reloaded, the app can serve the previous release's version string. This is the most operationally dangerous failure mode because it silently corrupts release tagging and deploy verification.
  • Version-string semantics: dev branches return dev-<branch>@<ref> rather than a semver, so any consumer that parses or compares versions must handle that shape. Do not build logic that assumes semver.
  • Historical 1.x failure modes (malformed generated class names, composer remove breakage, filesystem-specific install failures, global-vs-local plugin interference) are gone in 2.x but will reappear if anyone pins to a 1.x version for legacy reasons.

Ramp-up

  • Developer ramp-up is trivial — a single static method with one argument. Any Laravel developer is productive in minutes.
  • The non-obvious knowledge that must be written down: (a) the returned string is version@ref and may be a dev-* branch name; (b) the value is pinned at install time and requires OPcache reset on deploy; (c) the wrapper is the only sanctioned call site; (d) the removal path is Composer\InstalledVersions. Without (a)–(d) documented, the package will accumulate ad-hoc call sites and outlive its usefulness.
  • Recommended team-facing artifact: a short ADR plus the wrapper's docblock. Roughly half a day of writing, and it is what determines whether this ends up as a tidy one-line dependency or a diffuse one.
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.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin