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

Hash Ids Bundle Laravel Package

jasonbradley/hash-ids-bundle

Symfony bundle wrapping the hashids library to encode numeric IDs into short, reversible, non-sequential hashes—useful for hiding database IDs in URLs and public APIs. Adds service and Twig integration for encoding and decoding throughout a Symfony app.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit — poor, and mislabeled. Despite the request framing this as a Laravel/PHP package, jasonbradley/hash-ids-bundle is a Symfony2 bundle, not a Laravel package. It ships a Bundle subclass and a DependencyInjection extension registered through Symfony's kernel — neither of which Laravel's service container consumes. There is no ServiceProvider, no config/*.php, no facade. Installing it in a Laravel app gives you an inert vendor directory. The only genuinely reusable asset is its transitive dependency on hashids/hashids, which is a framework-agnostic PHP library that Laravel can use directly.

Integration feasibility — low as-is, high if you skip the package. Two viable paths:

Path Effort Verdict
Install the bundle and shim Symfony DI into Laravel Multi-day, brittle, drags in symfony/http-kernel Reject
composer require hashids/hashids, wrap in a ~60-line service provider + facade + Eloquent cast 0.5–1 dev-day Recommended
composer require sqids/sqids, same wrapper 0.5–1 dev-day Recommended if greenfield

Functionally the bundle offers nothing the underlying library does not — it is a container-registration wrapper for a stateless pure function.

Technical risk — high, concentrated in abandonment. Release history ends 2015-08-05, which implies a Symfony 2.x-era composer.json with PHP ~5.3/~5.4 constraints and no ^7/^8 support. Modern Laravel (10/11/12) runs PHP 8.1+, so composer install will either fail the platform check or require --ignore-platform-reqs, at which point you are running unmaintained 2015 code on PHP 8 with zero test coverage against your runtime. Combined signals: 0 stars, 0 dependents, score 0.13. There is no evidence of a second pair of eyes on this code, no security disclosure path, and no human to merge a patch. For code on the request path of every public URL, that is an unacceptable supply-chain posture for a feature whose entire value is a few lines of hashing.

Separately, evaluate the underlying concept rather than just the wrapper: Hashids is reversible obfuscation, not security. Anyone with the salt can enumerate. It also does not prevent enumeration if your IDs are dense and the salt leaks — and salt leakage via a committed .env or a stack trace is the common failure. If the requirement is "unguessable," Hashids/Sqids is the wrong tool; use a random opaque token column with a unique index.

Key questions for the product owner:

  1. Is the goal cosmetic (don't show customers id=1) or security (prevent enumeration/scraping)? Different answers change the design entirely.
  2. Do we need to decode incoming public IDs back to integers, or only encode outbound? Decode-on-input creates a failure path on every route.
  3. What happens to already-shared links if we rotate the salt? Is link permanence a contractual expectation?
  4. Multi-tenant: one global salt, or per-tenant salt to prevent cross-tenant ID translation?
  5. Are these IDs ever used as cache keys, idempotency keys, or exported to partners? If so, stability requirements tighten.

Integration Approach

Stack fit. Poor at the package level, good at the library level. Laravel's container, config repository, and Eloquent casting are all sufficient to host Hashids cleanly; the Symfony bundle abstraction adds nothing and costs a heavy transitive dependency (symfony/http-kernel) inside a Laravel app.

Migration path. Treat this as a build, not an adopt:

  1. Do not add the bundle to composer.json. Record the decision and rationale in the ADR so a future engineer doesn't rediscover the repo and try again.
  2. Add hashids/hashids (or sqids/sqids) as a direct dependency — one package, no framework coupling.
  3. Publish config/hashids.php with salt, min_length, alphabet, sourced from env. Fail fast at boot if salt is empty in non-local environments.
  4. Bind a singleton in a service provider; expose a facade or, preferably, inject a small PublicIdEncoder interface so call sites stay testable and the vendor is swappable.
  5. Add an Eloquent accessor/cast (e.g. public_id) and a route-binding resolver so controllers receive the model, not the hash string.
  6. Keep integer primary keys. Hashids belongs at the serialization boundary only — URLs and API payloads. Do not migrate PKs to hashes; you would lose index locality and break every join for zero benefit.

Compatibility. The bundle's Symfony2/PHP 5.x constraints are the blocker; the library underneath runs fine on PHP 8. Verify the exact hashids/hashids major version you land on — the min_length/alphabet API and decode-failure semantics (empty array vs. exception) have shifted across majors, and a silent behavior change here produces dead links, not a test failure, unless you write the contract test.

Sequencing. Ship in this order to cap blast radius:

  • Phase 1 (internal, ~1 week): encoder service + unit tests for round-trip and known-vector stability. No route changes.
  • Phase 2: outbound serialization only — API responses and share links emit public_id, inbound routes still accept integers. Nothing can break.
  • Phase 3: enable decode-based route binding behind a feature flag on one low-traffic resource.
  • Phase 4: roll out to remaining resources; keep integer routes alive for a deprecation window (min. 90 days) with 301 redirects.

Operational Impact

Maintenance — the dominant cost driver. Owning a ~60-line wrapper is less total maintenance than owning a vendored 2015 bundle you must patch for PHP 8, because the wrapper is code you wrote and understand, while the bundle is code nobody maintains. Budget roughly 2–4 hours per year for the wrapper (dependency bumps) versus an open-ended liability for the bundle on every PHP or Laravel major upgrade. Note the underlying hashids/hashids is itself in low-activity maintenance and has a designated successor (sqids/sqids); if this feature is strategic, start on Sqids and skip the eventual second migration.

Support. No upstream support exists — 0 stars, 0 dependents, last commit a decade ago. Any defect becomes an internal ticket with an internal owner. This is acceptable for a well-tested 60-line wrapper; it is not acceptable for third-party code you cannot read in one sitting. Assign a named owner in the team's service catalog either way.

Scaling. Effectively a non-issue. Encoding is CPU-bound, O(n) in the integer's digits, sub-microsecond, in-process, no I/O, no external service, no shared state. It will not be a bottleneck at any plausible request volume. The real scaling constraint is entropy collapse: Hashids with a short min_length on a densely-allocated integer space produces short, guessable-looking strings. If enumeration resistance matters, raise min_length — which is a config change that breaks every previously issued link. Decide min_length once, before launch, and treat it as immutable.

Failure modes to design against:

Failure Symptom Mitigation
Salt rotation Every historical link 404s; silent, total, irreversible Salt in secrets manager, versioned (salt_v1, salt_v2) with dual-decode during rotation windows
Salt committed to repo or leaked in a stack trace Full enumeration of all records Never echo salt; redact in exception handlers; treat as a sev-2 incident
min_length/alphabet change Same as salt rotation Pin in config; add a CI test asserting stable output for fixture IDs
Decode failure returns empty/null Route binding 404s or, worse, binds the wrong model Explicit try/catch → 404; never (int) cast a failed decode to 0
Hashids used for authorization Users reach other tenants' records when salt is shared Hashids is never an access control; enforce ownership on the integer model lookup
Hashids used as a cache or idempotency key Key instability across config changes Forbid by convention; keys stay integer

Ramp-up. Low. A mid-level Laravel engineer with no prior Hashids exposure can implement and test the wrapper in under a day given an existing service-provider pattern in the codebase. The learning cost is not the library — it is the operational discipline around salt immutability and link permanence, which is a 30-minute design conversation, not a training program. The bundle itself offers no ramp-up advantage, since using it correctly still requires understanding the same library.

Recommendation. Do not adopt jasonbradley/hash-ids-bundle. It is a 2015 Symfony2 container wrapper with no maintainers, no consumers, and no compatibility with the target stack. Deliver the underlying capability — short public identifiers — by depending on the Hashids (or Sqids) library directly behind a thin, tested, internally-owned Laravel service provider, with the salt in a secrets manager and a CI-enforced output-stability test. Estimated cost: 1–2 dev-days end to end, versus an open-ended platform-upgrade liability for a package that provides no functionality you cannot write in an afternoon.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle