krystal-sf/plugin-manager
A plugin manager for Laravel and PHP applications that handles plugin discovery, registration, activation, and lifecycle management. It provides a clean API for installing, enabling, and disabling plugins so you can extend your application with modular, self-contained packages.
Architecture fit. The critical finding for a TPM is a framing contradiction that must be resolved before any commitment: the package is titled a Symfony Advanced Plugins Manager in its own description, its vendor namespace (krystal-sf) reads as "Krystal Symfony," and its repository lives on GitLab under plugins-manager — yet the package is described here as a Laravel package. Both cannot be true in the way that matters. If the artifact is Symfony-based, it is not a drop-in Laravel dependency; it is a Symfony Kernel/DI-container citizen whose plugin discovery, manifest parsing, and enable/disable lifecycle overlap with what Laravel already expresses through service-provider auto-discovery and package discovery. A TPM should treat this as an architecture evaluation before an integration one. The decision to adopt is really the decision to make the product's integration layer a first-class platform concern — build a plugin surface versus ship a fixed API — and that is a roadmap-shaping call, not a library selection. The package's feature list (auto-discovery, runtime enable/disable, manifest metadata, artisan-style scaffolding) is genuinely the tedious part to build, which is why it merits evaluation at all.
Integration feasibility. Low to moderate, and gated on unknowns. Observable signals are poor: zero stars, zero dependents, a score of 0, and a repo URL that does not pluralize consistently with the package name — a smell worth resolving before anyone writes a composer constraint. Feasible paths, in ascending cost: (1) adopt natively if the target is genuinely Symfony; (2) bridge into Laravel by running Symfony's DI alongside Laravel's container or wrapping the manager behind an adapter — non-trivial, and the seam becomes the long-term maintenance liability; (3) read the manifest schema and lifecycle design and reimplement on Laravel primitives — highest confidence, lowest dependency risk, a few days of engineering. For a Laravel-native team, path 3 is almost always correct.
Technical risk. Rated high, driven by provenance rather than reviewed code quality. The package is single-vendor, has no visible community, no dependents to pressure-test upgrades, unknown release cadence, and an ecosystem mismatch with the stated target stack. A plugin manager is load-bearing infrastructure: it sits on the boot path and inside the container, so a defect there fails the whole application rather than one feature. The sharper edge is security — plugin systems are arbitrary-code-execution-by-design, so manifest validation, signing/allowlisting, and filesystem permissions become our problem regardless of what the package provides. The extraction from Krystal's own hosting product is a reasonable provenance signal that it solves a real control-panel problem, but it also means it was shaped around their requirements, not ours.
Key questions.
nwidart/laravel-modules?Stack fit. Assume Symfony is the real target until proven otherwise. On Symfony, fit is natural: bundles, tagged services, and compiler passes are exactly the substrate this package expects. On Laravel, fit is poor at the container layer and only reasonable at the domain layer — plugin discovery, enable/disable state, manifest parsing, and an admin surface. The two answers produce entirely different estimates, so the TPM's first job is to force the decision rather than let a spike paper over it. Consider it only when runtime discovery and per-environment or per-tenant activation are genuine requirements, or when inter-plugin dependency awareness is needed — neither of which naive provider discovery provides.
Migration path. If adopting on Symfony, install into a single non-critical service first, register one internal plugin behind a flag, and observe boot time and container compile behavior. If the goal is Laravel, do not migrate the package — migrate the concept. Define our own manifest contract (name, version, provider class, required host version, capabilities), implement discovery over a plugins/ directory, and register each enabled plugin's provider at boot. That is a handful of engineering days and eliminates the dependency and its bus factor entirely.
Compatibility. Treat as unverified. Before committing, pin down the PHP minor-version ceiling, supported framework majors, Composer 2 behavior, and whether the manager assumes a particular autoloading or cache-warmup model. For a Laravel bridge, add config-cache interaction, queue-worker and Octane safety (plugin state must not leak across requests), and whether registration happens before or after Laravel's package discovery.
Sequencing.
Maintenance. The realistic posture is we own it. Zero dependents means no upstream pressure to keep releases current, no community patch flow, and no early warning when it breaks against a new PHP or framework release. Budget a named internal owner and a fork-on-sight policy: vendor the code or mirror the repo so a deleted GitLab project is an inconvenience, not an incident. Version-pin exactly; avoid floating constraints on the boot path.
Support. No observable commercial support, no visible issue traffic, no stars. The escalation path is "read the source." That is acceptable for a small internal tool and unacceptable for anything customer-facing or revenue-path — set that expectation with stakeholders explicitly now rather than letting it surface during an outage.
Scaling. Two dimensions. Runtime: plugin managers add discovery I/O and container work at boot, a cost paid per request or per worker rather than per activation — measure it and cache aggressively (compiled container, hashed manifest cache). Organizational: the real ceiling is plugin count and contributing teams. Past roughly a dozen plugins across multiple owners you need versioned plugin APIs, a deprecation policy, and a compatibility test matrix, none of which this package will supply. Plan to build them, and treat that as scope, not surprise.
Failure modes. Enumerate and mitigate: boot-path failure (one malformed manifest takes the app down — per-plugin try/catch, strict schema validation, disable-all escape hatch); version skew (plugin written against an older host API loads silently — enforce a host-version constraint at load); dependency cycles (hangs or partial registration — topological sort plus cycle detector); cache staleness (enabled set cached from a prior deploy — key caches on a manifest hash); upstream abandonment (own the fork); and security, the headline risk — plugins are code execution, so require signed or allowlisted plugins, run with least filesystem privilege, and never let the plugin directory be web-writable.
Ramp-up. For a Symfony-fluent engineer, one to two days to productivity. For a Laravel-only team, add roughly a week for Symfony DI and compiler-pass concepts before the package itself even makes sense — which is itself the strongest argument for the reimplement-on-Laravel-primitives path. Deliverables to document regardless of path: the manifest contract, the trusted-plugin onboarding checklist, and a disable-all runbook.
Recommendation. Do not adopt as a dependency on the strength of the repository metadata alone. Run a scoped spike (≈1 engineer, 2 weeks) answering two questions — does the plugin contract fit our tenancy and deployment model, and is the code of a quality we would accept on the boot path? Proceed as a dependency only if both are yes; otherwise use it as a reference design and own a thin Laravel-native loader ourselves.
How can I help you explore Laravel packages today?