pushery / polyslug-for-laravel
Polymorphic, multilingual routable identity for Eloquent — leak-safe IDs, per-locale slugs, and hreflang out of the box.
Requires
- php: ^8.4
- ext-ctype: *
- ext-json: *
- ext-mbstring: *
- illuminate/collections: ^13.0
- illuminate/console: ^13.0
- illuminate/container: ^13.0
- illuminate/contracts: ^13.0
- illuminate/database: ^13.0
- illuminate/filesystem: ^13.0
- illuminate/http: ^13.0
- illuminate/routing: ^13.0
- illuminate/support: ^13.0
- illuminate/view: ^13.0
- sqids/sqids: ^0.5.0
Requires (Dev)
None
Suggests
- laravel/head: Lets a Polyslug model describe its own <head>: Head::polyslug($model) writes the canonical URL, the reciprocal hreflang set, the Open Graph locale set and the robots directive from the model's own slug data. Needs Laravel 13.17+, which is laravel/head's own floor - Polyslug itself needs only 13.0.
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v0.18.9.x-dev
- v0.18.9
- v0.18.8
- v0.18.7
- v0.18.6
- v0.18.5
- v0.18.4
- v0.18.3
- v0.18.2
- v0.18.1
- v0.18.0
- v0.17.1
- v0.17.0
- v0.16.0
- v0.15.0
- v0.14.0
- v0.13.0
- v0.12.0
- v0.11.0
- v0.10.0
- v0.9.0
- v0.8.2
- v0.8.1
- v0.8.0
- v0.7.0
- v0.6.0
- v0.5.1
- v0.5.0
- v0.4.0
- v0.3.0
- v0.2.1.x-dev
- v0.2.1
- v0.2.0
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
This package is auto-updated.
Last update: 2026-09-14 11:23:54 UTC
README
Polyslug
Polymorphic, multilingual routable identity for Eloquent. Pretty URLs that are safe to expose, safe to rename, and correct across languages — with leak-free IDs, self-healing canonical redirects, and hreflang built in.
/blog/laravel-routing-explained_aB3xK
└──────── slug ─────────┘ └id─┘
changeable, localized, SEO-friendly stable, opaque, resolves the model
A slug should be free to change. A URL should never break. Those two goals usually fight each other. Polyslug settles the fight by splitting a URL into two independent parts — a human-readable slug (pretty, per-locale, editable) and a stable opaque identity (an encoded token that resolves the model). Rename the slug all you like: the identity still resolves, and old URLs redirect themselves to the new canonical one.
Install
composer require pushery/polyslug-for-laravel php artisan migrate
Mark a model as sluggable, point a route at it, and you are done:
#[Polyslug(source: 'title')] class Page extends Model implements Sluggable { use HasPolyslug; } Route::polyslug('/pages/{page}', [PageController::class, 'show'])->name('pages.show');
Rename the page and the old URL 301s to the new one, by itself.
Why Polyslug?
- 🔒 Leak-safe IDs by default. URLs carry an encoded token, not
/pages/1523. No exposed row counts, no enumerable primary keys. The default encoder issues a random, unguessable token per row — the only shipped encoder that makes that claim true end to end. The choice is yours, though: Sqids, UUID, ULID, the raw key, or your own. - 📏 URLs as short as you want them. The URL is
{slug}_{token}by default, and both halves are yours to drop or shrink:slugless: truemakes it the token alone (/lists/k3f9dlq7),idLess: truemakes it the slug alone, and the token's length and alphabet are settings — per application or per model. A length that runs out of tokens widens by a character instead of failing, so a short one is a real choice. Need the shortest URL there is? A counted scheme hands out0,1, …z, then00. - ♻️ Self-healing URLs. Rename freely. A stale slug on a
GET/HEADrequest is301-redirected to the current canonical URL automatically — no redirect tables to hand-maintain, no dead links, no lost link equity. - 🌍 Multilingual with hreflang out of the box. One slug per locale, and a
reciprocal
hreflangset (plusx-default) generated from the same resolver that builds your canonical URL — so they can never drift apart. - 🧩 Polymorphic routing. Serve every content type — pages, articles, products —
through a single
{type}/{polyslug}route and one registry. - 🧭 Stable resolution. Route-model binding decodes the identity, not the slug, so
a mistyped or outdated slug still finds the right model (then redirects). An unknown
or malformed token is a clean
404— never a fuzzy match. - 🏢 Scoped uniqueness. Uniqueness can be scoped per tenant, per locale, per category — whatever columns you name.
- 🗂️ History, events & immutability. Superseded slugs are kept so old URLs keep
resolving; a
SlugChangedevent fires on every change; slugs can be frozen. - 🤝 Writes its own
<head>vialaravel/head. Install Laravel's<head>package andHead::polyslug($model)fills in the canonical URL, thehreflangset, the Open Graph locales and arobotsdirective for models your visibility gate hides. Optional — Polyslug requires nothing beyond slimilluminate/*components either way. - ✅ Proven on the databases you deploy to. The one-current-slug guarantee ships as a functional partial unique index on PostgreSQL and SQLite and as generated key columns on MySQL — two genuinely different mechanisms, and the suite proves both against real PostgreSQL 18 and MySQL 8.4 servers rather than inferring one from the other.
Documentation
Full docs at docs.pushery.com/polyslug-for-laravel.
- Installation — requirements, the migration, publishing
- Quick start — a sluggable model and a self-healing route
- Features — encoders, hreflang, nested paths, sitemaps, short links
- laravel/head — canonical URL, hreflang and indexability in Laravel's
<head>package - Recipes — twelve app shapes wired end to end
- Reference — every config key, option, command, event and contract
Requirements
- PHP 8.4+
- Laravel 13+ — 13.17+ only for the optional
laravel/headintegration, which is that package's own floor, not Polyslug's - PostgreSQL 18+, MySQL 8.4+, or SQLite — the uniqueness guarantees are enforced natively on each, and the full suite runs against all three. So Polyslug works on Laravel Cloud (serverless Postgres + MySQL 8.4 LTS) with no extra configuration.
Security
Please review the security policy and report vulnerabilities privately rather than opening a public issue.
Built by Pushery
This package is built and maintained by Pushery — a Berlin-based studio building Laravel applications, SaaS products, and open-source tools.
Building a Laravel UI? WireKit, Pushery's open-source Livewire component kit, gives you a polished component library out of the box. Browse the rest of our work at pushery.com.
License
The MIT License (MIT). See LICENSE for details.