Skip to content

Repository files navigation

@oratis/rate-limit

npm version bundle size license types

A zero-dependency, in-memory sliding-window rate limiter for Node. One small file, fully typed, self-pruning so it won't leak memory. Perfect for protecting an API route, a queue worker, or a CLI on a single instance — no Redis required.

  • 🪶 Zero dependencies, tiny footprint
  • 🎚️ True sliding window (not a coarse fixed bucket)
  • 🧹 Self-pruning — an unref'd timer sweeps stale keys; never keeps your process alive
  • 🧰 Class API (peek / reset / dispose) and a one-liner
  • 📦 Ships ESM + CJS + types

Single-process by design. Behind a load balancer each instance limits independently — fine for coarse abuse protection; use a shared store (Redis) when you need a strict global limit.

Install

npm install @oratis/rate-limit

Quick start

import { rateLimit } from "@oratis/rate-limit";

// Allow 100 requests per minute per IP.
const { allowed, remaining, resetMs } = rateLimit(ip, 100, 60_000);
if (!allowed) {
  return new Response("Too Many Requests", {
    status: 429,
    headers: { "Retry-After": String(Math.ceil(resetMs / 1000)) },
  });
}

Class API

Reach for RateLimiter when you want peek, reset, or explicit lifecycle control:

import { RateLimiter } from "@oratis/rate-limit";

const limiter = new RateLimiter({ limit: 5, windowMs: 10_000 });

limiter.check("user:42");   // record a request → RateLimitResult
limiter.peek("user:42");    // inspect without recording
limiter.reset("user:42");   // forget one key
limiter.reset();            // forget everything
limiter.dispose();          // stop the prune timer when you're done

RateLimitResult

Field Type Meaning
allowed boolean Whether the request is within the limit.
remaining number Requests left in the current window (0 when blocked).
resetMs number Ms until capacity frees up (great for a Retry-After header).

new RateLimiter(options)

Option Type Default Description
limit number Max requests per rolling window (> 0).
windowMs number Window length in ms (> 0).
pruneIntervalMs number 300000 Stale-key sweep interval. 0 disables the timer.

How it works

Each key keeps the timestamps of its requests. On every check, timestamps older than windowMs are dropped; if what remains is below limit, the request is allowed and recorded. This gives a true rolling window — no burst at the fixed-bucket boundary that naive counters suffer from.

License

MIT © oratis

About

Zero-dependency in-memory sliding-window rate limiter for Node — tiny, typed, self-pruning.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages