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

Symfony Route Usage Laravel Package

symplify/symfony-route-usage

Symplify Symfony Route Usage helps identify unused routes in Symfony applications by scanning code and templates for route references. Use it to audit routing configs, remove dead endpoints, and keep route definitions clean and maintainable.

View on GitHub
Deep Wiki
Context7

Getting Started

Set expectations first: symplify/symfony-route-usage is a Symfony bundle, not a Laravel package. It lives under deprecated-packages, has no dependents, and is unmaintained. You cannot composer require it into a Laravel app and get working behavior — the service provider, route collector, and console command all bind to Symfony's RouterInterface and EventDispatcher. Treat it as a reference implementation of the "dead route detection" pattern rather than a dependency.

Where to look first (in this order):

  1. README.md — confirms the actual console command name and the storage strategy (whether it logs hits to the DB, a file, or decorates the router). This determines whether the concept is portable to Laravel at all.
  2. src/ service registration — find the compiler pass / extension. The interesting bit is how it hooks into route matching; that's the part you'd re-implement with Laravel middleware.
  3. bin/console list (in a throwaway Symfony sandbox) — the bundle registers a reporting command (something like route:usage / route-usage:report); run it once against a real app to see the output shape.

First use case for a Laravel dev: don't install it. Open php artisan route:list side by side with your access logs (or Laravel Telescope's request list) for a week, and eyeball which named routes never appear. That's the entire value proposition this package automates — and 90% of the benefit with 0% of the abandoned dependency.

Implementation Patterns

Pattern 1 — Port the concept as middleware (recommended for Laravel).

Create a route_usage table (route string, hits integer, last_seen_at timestamp) and a lightweight middleware:

// app/Http/Middleware/TrackRouteUsage.php
public function handle(Request $request, Closure $next)
{
    $response = $next($request);

    if ($route = $request->route()) {
        $name = $route->getName() ?? $route->uri();

        DB::table('route_usage')->upsert(
            [['route' => $name, 'hits' => 1, 'last_seen_at' => now()]],
            ['route'],
            ['hits' => DB::raw('hits + 1'), 'last_seen_at' => now()]
        );
    }

    return $response;
}

Register it as terminable or wrap it in dispatchAfterResponse so it never adds latency to the response.

Pattern 2 — A comparison command.

// app/Console/Commands/UnusedRoutes.php
$defined = collect(Route::getRoutes())
    ->map(fn ($r) => $r->getName() ?? $r->uri())
    ->filter();

$used    = DB::table('route_usage')->pluck('route');
$unused  = $defined->diff($used);

$this->table(['Unused route'], $unused->map(fn ($r) => [$r])->all());

Schedule this weekly (->weeklyOn(1, '09:00')) and dump the output into Slack. Anything unused for 30+ days is a deletion candidate.

Pattern 3 — CI gate.

In the Symfony original this is a command that exits non-zero when unused routes exist. Mirror it in Laravel: make the command return self::FAILURE when $unused->isNotEmpty(), then run it in a PR job. Guard it with a baseline file (storage/unused-routes-baseline.json) so you ship the gate after the first cleanup, otherwise every PR fails on your existing debt.

Pattern 4 — If you genuinely need the Symfony version on a Symfony service, register the bundle in config/bundles.php, run the report against staging, and treat the output as a one-off audit. Don't wire it into production request handling — the deprecation means you're adopting an unpatched surface.

Integration tip: whatever you build, key on route name, not URI. URIs change when you add {id} constraints or a prefix; names are the stable identifier you'll actually delete by. Keep the URI as a secondary column so you can still map unnamed routes back to a controller.

Gotchas and Tips

  • Symfony-only, deprecated, zero dependents. No Symfony 6/7 support guarantees, no security patches, no issue triage. Verify composer show symplify/symfony-route-usage resolves against your framework version before you write any code assuming it works.
  • "Unused" ≠ dead. A route with no traffic may be a webhook, healthcheck, OAuth callback, or a route hit only during seasonal jobs. Always maintain an ignore list — _profiler, _wdt, health, horizon.*, telescope.*, storage.local, signed-URL download routes.
  • CLI and queue traffic doesn't go through HTTP middleware in some setups. If you generate URLs or dispatch requests from console commands, those routes look unused. Also consider URL::signedRoute / temporarySignedRoute consumers.
  • Route model binding and fallback routes swallow traffic invisibly — the matched route is the fallback, not the one you intended. Log the controller action too, not just the name.
  • Performance: the naïve version writes to the DB on every request. Use upsert, batch in a queue via dispatchAfterResponse, and sample (e.g. one write per route per minute) if traffic is high.
  • Debugging "why is this route reported unused": check middleware ordering. If TrackRouteUsage sits before SubstituteBindings / ThrottleRequests, it may never fire on 404/429 responses. Log after $next($request) and inspect $response->getStatusCode() to distinguish "never called" from "always errored".
  • Storage drift: route:cache doesn't touch your usage table, so a fresh deploy against a persisted DB looks stable — but a new environment starts empty and flags everything as unused. Never run the gate before the table has a full deployment cycle of data.
  • Extension points worth stealing from the original: the router decorator (wrap RouterInterface::match to record hits without HTTP middleware) is a cleaner design than middleware if you're on Symfony — it catches subrequests and ESI fragments middleware misses.
  • Deletion safety: before removing an "unused" route, grep the codebase for route('name'), to_route('name'), hardcoded URL strings, and href="{{ route(...) }}" in Blade. The tracking only sees inbound traffic, not outbound references that are themselves dead code — remove the caller first, then the route.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource