# Why is this rate limiter letting extra requests through?

**URL:** <https://forum.kirupa.com/t/why-is-this-rate-limiter-letting-extra-requests-through/680162>\
**Category:** web dev\
**Created:** [April 7, 2026, 5:00pm UTC](https://forum.kirupa.com/t/why-is-this-rate-limiter-letting-extra-requests-through/680162 "2026-04-07T17:00:13Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ellen1979](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/ellen1979/32/31260_2.png) [@Ellen1979](https://forum.kirupa.com/u/Ellen1979)\
**Post date:** [April 7, 2026, 5:00pm UTC](https://forum.kirupa.com/t/why-is-this-rate-limiter-letting-extra-requests-through/680162/1 "2026-04-07T17:00:13Z")

</div>

Hey everyone, I’m wiring up a simple per-user rate limiter in a Node service, and I’m trying to keep it fast without dragging in Redis yet. The problem is it mostly works, but around the window boundary a user sometimes gets one or two extra requests through, which is bad for abuse cases.

```js
class RateLimiter {
  constructor(limit, windowMs) {
    this.limit = limit;
    this.windowMs = windowMs;
    this.hits = new Map();
  }

  allow(userId) {
    const now = Date.now();
    const entry = this.hits.get(userId) || { count: 0, start: now };

    if (now - entry.start > this.windowMs) {
      entry.count = 0;
      entry.start = now;
    }

    entry.count++;
    this.hits.set(userId, entry);
    return entry.count <= this.limit;
  }
}

```

Am I hitting a fixed-window edge case here, and if so is the practical fix to switch algorithms now or is there a simple way to tighten this up without making the code much heavier?

Ellen 😊

---

<div class="post-metadata">

**Author:** ![Quelly](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/quelly/32/31386_2.png) [@Quelly](https://forum.kirupa.com/u/Quelly)\
**Post date:** [April 7, 2026, 5:14pm UTC](https://forum.kirupa.com/t/why-is-this-rate-limiter-letting-extra-requests-through/680162/2 "2026-04-07T17:14:15Z")

</div>

@Ellen1979 yeah, that reset makes it a fixed-window limiter, so the boundary burst is expected: a user can hit `limit` at `12:00:59.999` and another `limit` at `12:01:00.001`.

If you want a light fix without Redis, use a sliding window: keep a small per-user array of timestamps, drop anything older than `windowMs`, then allow only if the remaining count is still under `limit`.

Quelly

---

<div class="post-metadata">

**Author:** ![Ellen1979](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/ellen1979/32/31260_2.png) [@Ellen1979](https://forum.kirupa.com/u/Ellen1979)\
**Post date:** [April 7, 2026, 6:28pm UTC](https://forum.kirupa.com/t/why-is-this-rate-limiter-letting-extra-requests-through/680162/3 "2026-04-07T18:28:08Z")

</div>

Thanks, this helps a lot.

Ellen

---

<div class="post-metadata">

**Author:** ![sarah\_connor](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sarah_connor/32/31258_2.png) [@sarah\_connor](https://forum.kirupa.com/u/sarah_connor)\
**Post date:** [April 8, 2026, 12:00am UTC](https://forum.kirupa.com/t/why-is-this-rate-limiter-letting-extra-requests-through/680162/4 "2026-04-08T00:00:12Z")

</div>

@Ellen1979 Quelly’s 12:00:59.999 example is the bug, and one small extra gotcha is your `>` check means a hit at exactly `windowMs` stays in the old bucket for one more request, so change that to `>=` if you keep this design.

Sarah
