pecee/simple-router
A fast, lightweight PHP router with a simple, expressive API. Supports route groups, middleware, custom regex patterns, named routes and reverse routing, plus optional parameter binding and subdomain routing. Works with or without a framework.
What it is. pecee/simple-router is a standalone, MIT-licensed PHP router that deliberately mimics Laravel's routing API — route groups, prefixes, named routes, parameter regex constraints, middleware, resource routing, subdomains — but ships without a container, ORM, or application skeleton. It is PSR-7/PSR-15/PSR-17 aware and works as the dispatch layer in any PHP process.
Architecture fit. Fit is highly context-dependent and mostly inverse to how "Laravel" the target codebase is:
| Target context | Fit | Rationale |
|---|---|---|
| Existing Laravel app | Poor | Laravel's native router is wired into the container, middleware pipeline, route model binding, signed URLs, authorization gates, rate limiting, and route:cache. Substituting simple-router means rebuilding that glue and losing cached-route performance. |
| Legacy / procedural PHP app | Strong | Drop-in front controller, no framework migration required, familiar API for Laravel-trained devs. |
| Microservice or internal API gateway | Moderate–strong | Small footprint, no framework overhead, PSR-15 middleware composes cleanly. |
| Shared library needing routing | Weak–moderate | Forces a PSR-7 implementation choice on consumers; better to let the host app route. |
| WordPress / CMS plugin | Moderate | Works, but competes with the host's rewrite rules; needs careful base-path handling. |
The package's value proposition is familiarity without a framework, not replacing Laravel. Any proposal framed as "use this instead of Laravel's router" should be rejected at intake.
Integration feasibility. Composer-only install, no extensions, no service dependencies. It requires a PSR-7 implementation (e.g. nyholm/psr7 or guzzlehttp/psr7) plus PSR-17 factories, which the team must choose and own. Adapter work is the real cost: resolving route handlers through your DI container, translating your exception handler into its IExceptionHandler, and reconciling middleware ordering conventions (PSR-15 process() vs Laravel's handle()).
Technical risk. The dominant risk is lifecycle, not code quality:
The composite score (19.8) and opportunity score (30.8) are consistent with this read: a competent, low-momentum utility that is right for a narrow band of problems and wrong as a strategic dependency.
Key questions.
Stack fit. Adopt only where the router is genuinely the missing piece: a legacy monolith being strangled toward a framework, a set of small PHP services that share conventions, or a CLI/queue worker that needs URL matching without a full HTTP kernel. Do not introduce it alongside Laravel's router in the same request lifecycle — two routers means ambiguous 404/405 semantics and duplicated middleware.
Migration path. Use a strangler pattern rather than a rewrite:
Compatibility. Pin an exact version in composer.json (no caret range) and record it in the platform dependency register. Validate on the oldest and newest PHP versions in the support matrix, in CI, not locally. If the app already runs a PSR-7 stack, reuse those instances rather than adding a second implementation; if it does not, choose the PSR-7 library the rest of the org already standardizes on.
Sequencing. Four gates, roughly two to three sprints of effort for a mid-sized surface:
Treat Gates 1–2 as a go/no-go: if the adapter layer starts absorbing framework-grade complexity, the migration has lost its justification.
Maintenance. Assume we own the code in practice. Budget a recurring line item for dependency review each PHP minor release, and keep a named owner and a documented fork procedure (mirror the repo, apply security patches, publish under an internal namespace if needed). Pin the version and let Renovate/Dependabot open PRs that a human reviews — do not auto-merge.
Support. No commercial backing and no SLA; support is GitHub issues with no guaranteed response. Internal developers become the de facto second line. Ramp-up for a Laravel-fluent engineer is one to two days — the API is intentionally familiar — but they also need working PSR-7/PSR-15 literacy, which is the actual learning cost.
Scaling. Route matching is linear in the number of registered routes and negligible relative to typical controller work, so per-request overhead is fine at normal API volumes. The structural gap is the absence of Laravel-style compiled route caching: every request re-registers and matches routes. For high-QPS services with hundreds of routes, measure before committing; if it shows up, mitigate by splitting the route table per service rather than fighting the library. Horizontal scaling is otherwise unaffected — the router is stateless.
Failure modes to instrument and pre-plan for:
Ramp-up and recommendation. Low onboarding cost, low ongoing feature velocity upstream. Adopt for legacy/standalone PHP services where the alternative is hand-rolled routing; decline inside Laravel proper. Record it as a tactical dependency with an explicit review date tied to the next PHP minor release, and a standing replace-with-native-router trigger if upstream activity does not resume.
How can I help you explore Laravel packages today?