qopiku/filament-sqids
Filament plugin for Sqids: automatically encode and decode model IDs into short, obfuscated, URL-friendly strings. Integrates with Filament resources and tables to hide sequential primary keys while keeping routes and links clean and portable.
Architecture fit — korfra/filament-sqids is a thin adapter that swaps Filament's default numeric route keys for Sqids — short, obfuscated, reversible strings generated from integers. Architecturally it sits at the routing/serialization boundary: models expose a Sqid as getRouteKey(), Filament resource URLs render it, and inbound requests are decoded back to the primary key before binding. It does not touch persistence, so it stays out of the domain layer — which is the right shape for a presentation concern. The trade-off is that URL identity becomes a derived value, so every surface that constructs or consumes a Filament URL (tables, relation managers, notifications, exports, emails, embedded links) becomes an implicit dependency on that derivation.
Integration feasibility — Low effort. Composer install, optional config publish (alphabet, minimum length, blocklist), and a trait/interface on the models whose IDs you want obfuscated. No migrations, no schema change, no data backfill. A Laravel developer can spike this in under a day.
Technical risk — Three items dominate:
0.0.1 → 0.1.0, a pre-release minor bump. Under semver, 0.x makes no stability promise; any 0.2.0 may break config keys or trait signatures. Treat the API as unstable and pin exactly.Secondary risks: coverage gaps (does it handle nested/relation-manager routes, global search results, and Filament's own generated links consistently?), interaction with any other package that overrides route keys, and cache/CDN layers keyed on the raw path.
Key questions
Stack fit — Requires a modern Laravel (10/11) + PHP 8.1+ stack with Filament. If we're still on an older Filament minor or a PHP version below that floor, this is blocked outright — verify first, before any design work.
Migration path — Do not touch primary keys. Introduce sqids as a rendering concern only: keep integer PKs internally and in the database, apply the route-key trait per model, and roll out resource-by-resource rather than panel-wide.
Suggested path:
/admin/orders/123 to the sqid form. Cheap insurance, removes the "old links are dead" support load.Compatibility — Check for collisions with HasUuids/HasUlids, any custom resolveRouteBinding, and any place we hand-build Filament URLs by string concatenation. Audit caching: if we cache responses or pages by path, sqid URLs still cache fine, but cache-invalidation logic that assumes numeric segments needs review.
Sequencing — Pin 0.1.0 exactly in composer.json and hold off on composer update for this package until each new tag's diff has been reviewed. Pair adoption with contract tests asserting URL shape and round-trip decode, so any future 0.x breakage fails CI rather than production. Land this in a maintenance window, independent of other Filament upgrades — don't stack two risky changes in one deploy.
Maintenance — Small, single-maintainer package with a narrow surface area. Upside: low LOC means a fork is genuinely viable if the maintainer goes dark. Downside: no roadmap guarantee and no deprecation policy. Mitigation is to wrap usage behind our own trait or interface so the third-party dependency can be swapped for a hand-rolled implementation without touching every model.
Support — No commercial support; community issues only. On the plus side, the underlying Sqids algorithm is a stable, well-specified standard with library implementations in many languages, so the concept is safe even if this specific wrapper stalls.
Scaling — Negligible runtime cost — integer-to-string encoding per URL render, no additional queries and no schema change if the sqid is computed on the fly. Two things to watch: (a) sqid length grows with ID magnitude once IDs exceed the minimum-length floor, so very large tables yield longer URLs; (b) if anyone is tempted to add a persisted sqid column for indexing, that's a real storage and migration cost — resist it.
Failure modes
| Failure | Symptom | Blast radius | Mitigation |
|---|---|---|---|
| Alphabet / min-length changed | Every existing URL 404s | All shared links, emails, bookmarks, partner integrations | Freeze config in repo; redirect shim; treat as a breaking-change event |
| Pre-1.0 breaking release | Trait/config rename after composer update |
Panel routing across all resources | Exact pin + diff review + contract tests |
| Coverage gap (relation manager, global search) | Mixed numeric/sqid URLs | Inconsistent UX, broken deep links | Spike must enumerate every URL-generating surface |
| Decode errors on malformed input | 500 instead of 404 | Noisy alerts, possible info leak in error pages | Verify exception handling; test with garbage input |
| Misread as security | Team relaxes policy checks | Unauthorized data exposure | Document explicitly in onboarding: sqids are obfuscation, not authorization |
Ramp-up — Low. A Laravel developer is productive with it in half a day; the real cost is the team-wide conceptual correction that obfuscated IDs aren't secret. Add a line to onboarding docs and a code comment on the trait. Budget roughly one sprint-week end-to-end including spike, redirect shim, and contract tests.
Recommendation — Worth adopting for URL cosmetics if the driver is "don't expose sequential IDs," and only after the 0.0.1→0.1.0 diff is reviewed and the Filament version floor is confirmed. Pin exactly, freeze the config, and keep authorization in policies where it belongs.
How can I help you explore Laravel packages today?