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

Laravel Rate Limiter Laravel Package

aporat/laravel-rate-limiter

Add flexible rate limiting to Laravel routes and APIs with aporat/laravel-rate-limiter. Configure request limits, time windows, and custom keys, then protect endpoints via middleware using Laravel’s cache-backed storage. Ideal for throttling login attempts, webhooks, and public APIs.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit — The package lives at the HTTP middleware layer and delegates all state to Redis through a single Lua script per request. v6 modernizes the internals in ways that matter for a Laravel estate: config read through Illuminate\Contracts\Config\Repository, an immutable builder (the facade no longer leaks state between calls), and a singleton that holds no request state — i.e. Octane/RoadRunner-safe. It also stops maintaining a parallel Redis config and uses Laravel's Redis manager with named connections, TLS, cluster and REDIS_URL. The trade-off is that it puts Redis on the synchronous critical path of every limited route, which is a new hard dependency for those endpoints.

Integration feasibility — Low-to-moderate effort. Most policies express declaratively in routes via the validated middleware DSL (rate.limiter:second=,minute=60,hourly=1000,key=ip+route,name=api); the programmatic surface (RateLimit::with(), PendingLimit::attempt(), LimitResult, RateLimiter::attempt(), blockedFor()) covers multi-window and custom flows atomically, which was previously the awkward part. RateLimitExceeded and IpBlocked events give clean hooks into existing metrics. The real cost is not code volume but the removed API surface and the header contract.

Technical risk —

  • Wide breaking surface. Header names changed to X-RateLimit-Limit / -Remaining / -Reset; withRateLimitHeaders(), setRequestTag(), getRequestTag(), checkIpAddress(), the redis.* settings and Lumen support are gone. Old header names don't error — they disappear. Anything parsing them (client SDKs, mobile backoff logic, gateway rules, dashboards, contract tests) fails silently or degrades to naive retry.
  • Security remediation, not a routine bump. v5's default whitelist included 10.0.0.0/8, and with trust-all proxies any client could present a private address and be exempt entirely. If we run behind a load balancer that trusts forwarded headers, prior limiting may have been partially or wholly ineffective. This reframes the upgrade as a security fix with an exposure question attached.
  • Behavior change shifts baselines. Refused requests no longer increment the other windows (previously a per-second burst could lock a client out for the hour). Correct, but 429 volume and hourly counters will move and previously "stuck" clients will recover — this will look like an anomaly on existing dashboards.
  • Key correctness fixes are silent. Segment escaping (withUserId('a:b') no longer collides with withUserId('a')->withName('b')) and no shared bucket for missing IPs change which counters exist. Pre-existing collisions may have been masking abuse or over-limiting; expect key-space churn on cutover.
  • Cluster hash tags concentrate load. All windows for one subject share a slot by design (correct), which means a single abusive client maps to a single shard.
  • Failure mode is now an explicit product decision. on_redis_failure: open | closed (503) with failure_backoff_seconds.

Key questions —

  1. Who parses the rate-limit headers today, and do we control all of them? Is parallel header emission needed?
  2. Were we behind a proxy trusting X-Forwarded-For while the 10.0.0.0/8 whitelist was active — i.e. was v5 actually limiting anyone?
  3. Is Redis already a hard dependency for this tier, and which client (phpredis vs predis), standalone vs cluster? Who owns its SLO?
  4. What is the intended behavior on Redis failure, and does it differ by route class (auth/write endpoints vs read endpoints)?
  5. Is PHP 8.3 already our runtime floor, and which Laravel lines are in the supported CI matrix?
  6. Do the downgraded logs (one warning, path only, log_errors default false) remove data we currently alert on?
  7. Are there tenant-facing quota semantics — plan tiers, billing, SLA language — built on the old header values or old window semantics?

Integration Approach

Stack fit — Native Laravel throughout: service provider, publishable config, middleware alias, facade, events, config contract. Preferring Laravel's Redis manager over its own connection settings is the right call — it collapses two divergent Redis configs into one and inherits config/database.php, REDIS_URL, TLS, cluster and client choice for free. Fits cleanly alongside cache/queue/session on shared Redis, though isolation (separate database or instance) is worth considering given eviction risk.

Migration path —

  1. Baseline: inventory every rate.limiter usage and RateLimit:: call, capture a week of 429 rates and emitted header values.
  2. Republish config; migrate removed redis.* settings into a named Laravel Redis connection and reference it via connection (the named connection now wins over host/port/database defaults — a wrong database index silently limits against the wrong dataset).
  3. Replace removed APIs: withRateLimitHeaders() → headers config; setRequestTag()/getRequestTag() → name= / key= DSL params or RateLimit::with(); checkIpAddress() → whitelist config.
  4. Audit middleware parameters — they're now parsed and validated, so previously ignored values become failures. Every rate.limiter:* string needs a second look.
  5. Set on_redis_failure explicitly per route class rather than accepting a default.
  6. Move header consumers before flipping traffic; dual-emit old and new names at the edge if any client can't ship in the same window.

Compatibility — PHP 8.3+ is a hard floor; verify base images and any shared runtime before scheduling. Pin to a Laravel line covered by the CI lanes and confirm ext-redis is optional in our setup (predis path is tested, so it's viable). Lumen-based services cannot upgrade and remain on v5 — with the whitelist exposure unresolved on those. The header rename should be treated as a versioned public API change with a deprecation notice, not an internal refactor.

Sequencing — Runtime/PHP upgrade → Redis connection migration (behind a flag, verified against prod topology) → API surface swap + header dual-emit → middleware parameter audit → security defaults validated behind the real proxy chain → canary one route → full rollout. If step zero shows the v5 limiter was ineffective, treat that as an incident finding and fix the whitelist independently of the version upgrade rather than waiting for the full migration.

Operational Impact

Maintenance — Small, single-purpose dependency with a compact surface (config + middleware + a few APIs). The concern is churn: this package ships breaking minors, so pin exact versions and review each bump rather than floating ranges. Pint and PHPStan level 8 as separate CI jobs is a reasonable quality signal, and testing both Redis clients plus a redis:8 service image suggests the maintainer is exercising real paths.

Support — Diagnosis shifts from "package misconfigured" to "is Redis healthy". Runbooks need: named-connection validation, NOSCRIPT/EVALSHA behavior, cluster slot and script-propagation checks, and the open/closed setting documented per route. Error reporting is deliberately throttled to one warning per backoff window — good for log noise, but it means app logs are no longer a reliable outage signal; alert on Redis health and on the ratio of limited-to-unlimited traffic instead.

Scaling — One Lua round-trip per limited request: the ceiling is Redis RTT, not app CPU. Size connection pools accordingly and watch EVALSHA hit rate — fallback to EVAL after restarts or SCRIPT FLUSH is a latency spike, and in cluster mode every node needs the script. Hash tags pin all windows of a subject to one shard, so abusive clients create hot shards; multi-window policies multiply keys per subject. Confirm maxmemory-policy: noeviction — eviction under pressure silently resets limits and turns a protection mechanism into a no-op at exactly the wrong moment.

Failure modes —

  • Redis unavailable → closed returns 503 to all limited traffic (availability incident) or open serves unlimited (protection gap). Must be chosen per endpoint, not globally by accident.
  • Proxy/whitelist mismatch → fail-open exemption; verify the loopback-only default holds in the deployed topology and that client IPs resolve to the real caller, not the LB.
  • Named connection misconfiguration → limits enforced against the wrong Redis database, invisible until someone asks why quotas reset.
  • Custom key= composition in cluster → cross-slot errors if hash tags aren't preserved.
  • First deploy with strict parameter validation → a burst of 500s from any route with a malformed limiter string. Grep before shipping.
  • Key-escaping change → new counter keys at cutover; expect a one-time reset of every limit and a short window of doubled effective quota.

Ramp-up — Low for a Laravel-fluent engineer: alias plus a parameter string handles the common case in an afternoon. The genuine learning curve is semantic, not syntactic — what a limit means when four windows interact, why headers now describe the most restrictive one, and how blockedFor()/LimitResult compose. Budget half a day of team review against the upgrade guide plus a load test on the production Redis topology (including a failover drill with each on_redis_failure setting). Write the quota policy in product language first — "60/min, 5k/hour, keyed by user+route, 503 on Redis failure for auth routes" — so route files become transcription rather than design.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource