graham-campbell/throttle
Rate limiting for Laravel by Graham Campbell. Throttle provides middleware and a facade to limit requests and actions by key, IP, or route, backed by your cache driver, with configurable hit limits and decay times. Ideal for APIs and forms.
Architecture fit. Throttle slots into Laravel's existing HTTP middleware stack: a service provider, a Throttle facade, route/group middleware, a Throttles trait, and a config file with max-attempts and decay settings. No migrations, no new services, no UI. The adoption blast radius is one middleware alias per route group, which is the right profile for a security-adjacent control — cheap to add, cheap to remove, easy to reason about in review.
The architectural reality a TPM must internalize is that Laravel already ships this primitive: ThrottleRequests middleware, the RateLimiter facade, named limiters via RateLimiter::for(), per-user/per-IP keys, and standard Retry-After / X-RateLimit-* headers are all first-party. This package is a config-driven convenience wrapper over that. So the framing is not "do we need throttling" (we do) but "does a wrapper earn a third-party dependency." The defensible default is the framework; a package has to remove real, ongoing configuration spread to justify itself.
Integration feasibility. High but hard-gated on runtime. v11 supports only PHP 8.1–8.4 and Laravel 10–12, so Composer resolution is a binary gate — teams on PHP 8.0 or Laravel 9 are blocked until the platform upgrade ships. Realistically this is a sub-day integration for a competent Laravel engineer plus test coverage for boundary conditions; the effort is not in the wiring, it's in verifying behavior under concurrency and behind the edge.
Technical risk. Code risk is low; behavioral risk is where attention belongs, and it's asymmetric because the failure modes are silent.
array cache, each server counts independently and the effective limit multiplies by node count — correct in staging, decorative in production. Adoption implies a shared cache (Redis/Memcached) commitment that belongs in the platform roadmap.TrustProxies and CDN header handling, keys either collapse into one global bucket (site-wide 429s on normal traffic) or become spoofable via X-Forwarded-For (protection bypassed). Adoption introduces this misconfiguration risk; it should be an explicit acceptance criterion.Key questions.
RateLimiter::for() and throttle: that justifies a dependency? Name the gap or default to the framework.TrustProxies and CDN headers?Retry-After, or a bare 429?Stack fit. Non-negotiable: PHP 8.1–8.4, Laravel 10–12. Best fit is a Laravel 11/12 app on PHP 8.2+ already running Redis as a shared cache with TrustProxies configured for its edge. Worst fit is a multi-node app on file or array cache with no proxy configuration — there, the package installs cleanly and delivers no real protection, which is the most dangerous outcome because it looks like coverage.
Migration path. Prove the gap first. Spend half a day implementing login plus one API route group with core RateLimiter::for() and throttle:; adopt the package only if that falls short on a named requirement, and record the reason in the decision log. If adopting, wrap registration in a single config/service-provider abstraction so removal is a one-file change, pin an exact version, and enable on one low-risk route group before broadening.
Compatibility. Three things must be true in every environment including CI images and long-lived queue/Octane workers: the runtime matrix, a shared cache driver, and correct proxy/edge configuration. The array driver silently makes throttling per-process — that is a staging-only configuration, never production. Verify Composer resolution before committing to a release window; if the platform upgrade hasn't landed, the discussion is moot.
Sequencing. Order matters and is not compressible:
Retry-After, X-RateLimit-*, and documentation of what counts as a request.Steps 4 is the expensive half and is a product decision with support-cost implications, not a technical one.
Maintenance. Low code churn, but real ongoing owner attention. The package is single-maintainer with a low composite score and zero dependents, so we own regression detection. Budget a standing line item for dependency bumps tied to Laravel major releases, and treat "does this still track the framework's rate limiter behavior" as a per-upgrade check rather than assuming parity.
Support. The support surface is customer-visible once throttling is on. Support needs a documented answer for: what a 429 means, how long Retry-After is, whether limits differ by plan, and how to request an exception. Absent that, every throttled request becomes a ticket. The TrustProxies misconfiguration path is the highest-volume support risk — one bad proxy setting and normal users see 429s site-wide, which reads as an outage and will be escalated as one.
Scaling. Correct scaling is entirely a function of cache topology. A shared Redis/Memcached store scales horizontally with standard cache operational characteristics; per-node stores scale the limit, not the protection — N nodes means N× the intended allowance. Beyond that, app-level middleware handles abusive clients but not volumetric DDoS; adoption must not be allowed to close the WAF/edge conversation. Sliding windows, token buckets, per-tenant budgets, and cross-region coordination are gateway/service-mesh territory and should be explicitly out of scope.
Failure modes. Ranked by damage:
Ramp-up. Low technical ramp-up, moderate organizational ramp-up. Engineers absorb the API in an hour. The real work is discipline: a security-review checklist item ("are login, OTP, password-reset, and webhook routes throttled, and at what limit?"), a decision-log entry recording why the package was chosen over the framework primitive, and test coverage that fires N+1 concurrent requests against a limit of N and asserts the boundary holds and Retry-After is present. Exit criteria for adoption: identical enforcement across nodes, correctly shaped and documented 429s, and no abuse-prone route left unthrottled.
How can I help you explore Laravel packages today?