kefyusuf/laravel-bloom-gate
Laravel Bloom Gate adds Bloom filter-backed gates to Laravel, providing fast, memory-efficient authorization checks that plug into the framework's Gate system. Guard routes and actions with a lightweight probabilistic access-control layer.
Laravel Bloom Gate is a negative-lookup gate: a Bloom filter sits in front of an authoritative SQL store so that queries for values that definitely do not exist can be answered without touching the database. It targets PHP 8.3+ and Laravel 12/13 only.
Minimum setup:
composer require kefyusuf/laravel-bloom-gate:0.1.0-rc.2
php artisan vendor:publish --tag=bloom-gate-config
Pin the exact release-candidate version. This is the second RC, not a stable v1 and explicitly not a production deployment certification — treat any version constraint looser than exact as unsupported.
Where to look first:
First use case: an immutable filter over a table you can fully warm from the authoritative store — a unique-email check, a slug registry, a exists() guard on an identifier that is absent most of the time. Build it, warm it, route reads through the gate, fall through to SQL on a positive. That exercises the whole happy path with none of the mutable-write protocol risk.
Because Packagist registration and indexing are observed separately from the GitHub tag, verify what actually installed (composer show kefyusuf/laravel-bloom-gate, and check the installed commit) before assuming you are on rc.2.
Immutable filter for static key sets. Build the filter from a full authoritative read, then serve it read-only. This is the lowest-risk integration: no writer participation, no lease history, no prepared-write protocol. Refresh by rebuilding rather than mutating.
Coordinated prepared writes for mutable filters. If the underlying key set changes at runtime, every membership-entry writer must participate in the prepared-write protocol. Not most writers — every one. The package calls this out explicitly, and rc.2's README sharpens the legacy pre-add versus coordinated prepared-write distinction precisely because mixing them silently breaks the guarantee you think you have.
Gate-then-fallthrough read path. The pattern is always: ask the gate, and on a negative answer short-circuit; on a positive answer issue the authoritative query anyway. Bloom false positives are cheap and expected — they degrade to the unoptimised path. False negatives are the failure mode that actually loses data, which is why normalization and collation alignment matter so much.
Trusted negatives on the Redis profile. Redis-backed trusted negatives require the documented durable standalone-primary profile. If you are on Redis Cluster, you are outside what this candidate certifies — use a SQL-backed consumer instead.
Consumer selection by datastore. rc.2 verifies production-only Redis paired with MySQL, PostgreSQL and SQLite consumers, covering trusted negatives, authoritative fallback, known SQL commit and rollback outcomes, and rebuild. Pick the consumer matching your primary store and mirror its comparison semantics in the filter configuration.
Transaction-aware writes. Because commit/rollback outcomes are part of what rc.2 verifies, wrap filter writes in the same transactional boundary as the SQL write and test the rollback path deliberately. A filter entry that survives a rolled-back insert produces a permanent false positive; an entry lost on commit produces a false negative.
Measure before enabling. Instrument the negative-query ratio and the target datastore's indexed query cost first. The optimisation only pays on absent-heavy workloads, and only in query count — not universally in latency.
Rebuild as a routine operation. Rebuild from authoritative evidence after normalization changes, collation changes, bulk imports, or any suspected drift. Rebuild is the supported recovery path; incremental repair of inconsistent state is not.
The performance claim is narrow. In the local 1,000-query absent-value workload, SQL queries fell from 1,000 to 8. But on all-present queries the gate avoided zero SQL calls, and the Redis gate was slower than indexed local MySQL, PostgreSQL and in-memory SQLite. This is a query-avoidance mechanism, not a latency mechanism, and the release notes say so directly. Do not adopt it to make a fast indexed lookup faster.
Drain cost scales with retained lease history. Median writer drain validation went from roughly 0.16–0.20 ms with no retained leases to 2.33–2.86 ms with 1,000 released leases. These are development measurements, not throughput limits, but the shape is the point: long-running retained lease history is explicitly uncertified. Monitor and prune retained leases, and watch drain latency as history accumulates.
Inconsistent evidence is rejected, not repaired. rc.2 changed writer drain reads to reject inconsistent surviving lease/count evidence in Memory and Redis without repairing it. This is a safety improvement, but it means corruption surfaces as an error rather than self-healing. Build detection and a rebuild runbook before you need them.
Legacy pre-add is not a shortcut. It exists for pre-existing deployments, not as a convenience API for new code. Mixing it with coordinated prepared writes in the same filter produces a filter whose guarantees are undefined.
Collation mismatch creates false negatives. SQL comparison and collation must agree with the filter's normalization semantics. A case-insensitive MySQL column behind a case-sensitive filter — or trailing-space, accent, or Unicode normalization differences — will produce confident "definitely absent" answers for rows that exist. Align normalization deliberately, and prefer a conservative normalization if you cannot verify the store's behaviour.
Uncertified territory, enumerated. Redis Cluster, unobserved production deployments, long-running retained history, and MongoDB integration (unverified) are all outside the candidate's evidence. If your architecture lands in any of these, this RC is not your dependency yet.
Extension points worth knowing. The config tag is the primary surface; beyond it, the prepared-write participant contract and the rebuild path are the two places you will extend or wrap. Both are RC-era APIs and may move before v1 — keep the integration behind a thin internal wrapper so a version bump is a one-file change.
RC discipline. Pin the exact version, keep the integration small, and re-read the release notes on every candidate. rc.1 remains immutable and rc.2 deliberately tightened validation rather than adding features — expect the same posture toward correctness over convenience in subsequent candidates.
How can I help you explore Laravel packages today?