glhd/gretel
Gretel is a Laravel package for managing redirects and avoiding broken links. Define redirects in code, automatically catch 404s, route old URLs to new ones, and track hits with a simple, flexible API for keeping your app’s links healthy.
Gretel is a redirect manager: it catches 404s and turns them into 301/302s, backed by either a routes-file map or a database table. The 1.10.0 release only widens the framework constraint to Laravel 13 — no API changes — so the onboarding path below is identical for 1.9.x and 1.10.x.
composer require glhd/gretel
php artisan gretel:install # publishes config/gretel.php + the redirects migration
php artisan migrate
Register the middleware so it can inspect responses. On Laravel 11+/13 (bootstrap/app.php):
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\Glhd\Gretel\Http\Middleware\HandleRedirects::class,
]);
})
First use case — the one you'll reach for 90% of the time — is a static map of legacy URLs in routes/web.php:
Route::gretel([
'/old-pricing' => '/pricing',
'/blog/2020/hello' => '/blog/hello',
]);
Hit the old URL in a browser, confirm the 301, then check gretel_redirects in the DB to see the hit recorded. That's the whole loop.
Static map vs. database rows. Route::gretel([...]) is best for a bounded, known set of legacy URLs that lives in version control and ships with deploys. Reach for DB-backed redirects (Gretel::redirect('/old', '/new'), or inserting rows) when editors or a CMS need to create them at runtime, or when you're importing thousands of rows from an old site.
Slug history on Eloquent models. The highest-leverage pattern: when a model's slug changes, register the old one so links don't rot.
// in an observer or model event
Gretel::slug($model->getOriginal('slug'), $model->slug);
This is what makes Gretel worth installing over hand-rolled Route::redirect() calls — content URLs stay stable while editorial slugs churn.
Bulk import from a legacy system. Seed straight from a CSV/JSON dump in a one-off artisan command or seeder, then php artisan gretel:refresh in the deploy script so the cached map is rebuilt. Don't loop Gretel::redirect() inside a request.
Chains and pruning. Point every old URL directly at the final destination — never old → interim → new. Then use the recorded hits / last_hit_at columns to find redirects that haven't fired in a year and retire them (soft-delete preserves the history).
Testing. Nothing special is required; the middleware runs in feature tests.
$this->get('/old-pricing')->assertRedirect('/pricing');
$this->get('/pricing')->assertOk();
Deploy integration. After any migration or content import that touches redirects, run gretel:refresh. Adding that to your deploy script is the single most useful habit with this package.
web group) and after session/start-session middleware. Putting it in a narrow group means only those routes get redirect handling.gretel:refresh (or disable the cache in config/gretel.php) before debugging anything else.config/gretel.php — subclass it if you need extra columns, scopes, or per-tenant redirects. Custom middleware wrapping HandleRedirects is the sane place to add logging or A/B logic.How can I help you explore Laravel packages today?