
Research
/Security News
16 Malicious Firefox Extensions Steal Cryptocurrency Wallet Credentials
Socket found 16 malicious Firefox extensions designed to steal crypto wallet recovery phrases and private keys using cloned Rabby and OKX interfaces.
flex-rate-limit
Advanced tools
Universal rate limiting module for Node.js - supports any framework, multiple storage backends, flexible algorithms
A framework-agnostic Node.js rate limiting library with multiple algorithms, Memory / Redis / cache-hub backed storage, and Express-style middleware.
Documentation · 中文文档 · Examples
check() from Express, Koa, Egg.js, Hapi, Fastify, workers, queues, or any custom adapter.limiter.middleware() directly in Express-compatible stacks.CacheHubStore, or your own store adapter.allowed, limit, current, remaining, resetTime, and retryAfter.>=18.0.0npm install flex-rate-limit
Redis-backed usage:
npm install flex-rate-limit ioredis
cache-hub atomic backend usage:
npm install flex-rate-limit cache-hub ioredis
check()const { RateLimiter } = require('flex-rate-limit');
const limiter = new RateLimiter({
windowMs: 15 * 60 * 1000,
max: 100,
});
const result = await limiter.check('user:123');
if (!result.allowed) {
console.log(`Retry after ${result.retryAfter} ms`);
}
const express = require('express');
const { RateLimiter } = require('flex-rate-limit');
const app = express();
const globalLimiter = new RateLimiter({
windowMs: 15 * 60 * 1000,
max: 100,
});
app.use(globalLimiter.middleware());
const loginLimiter = new RateLimiter({
windowMs: 15 * 60 * 1000,
max: 5,
});
app.post('/api/login', loginLimiter.middleware(), (_req, res) => {
res.json({ message: 'login accepted' });
});
app.listen(3000);
Use check() and map the result to the framework's own middleware, hook, or pre-handler shape:
const { RateLimiter } = require('flex-rate-limit');
const limiter = new RateLimiter({
windowMs: 60 * 1000,
max: 60,
});
async function guard(ctx, next) {
const key = `user:${ctx.user?.id || ctx.ip}:${ctx.path}`;
const result = await limiter.check(key, { route: ctx.path });
if (!result.allowed) {
ctx.status = 429;
ctx.body = { error: 'Too Many Requests', retryAfter: result.retryAfter };
return;
}
await next();
}
See the runnable framework examples on GitHub and the quickstart guide.
The default store is fast and simple. Use it for single-process services, local development, tests, and cases where counters do not need to be shared across instances.
const limiter = new RateLimiter({
windowMs: 60 * 1000,
max: 100,
store: 'memory',
});
Use RedisStore when multiple application instances must share counters.
const Redis = require('ioredis');
const { RateLimiter, RedisStore } = require('flex-rate-limit');
const redis = new Redis(process.env.REDIS_URL || 'redis://127.0.0.1:6379');
const limiter = new RateLimiter({
windowMs: 60 * 1000,
max: 100,
store: new RedisStore({ client: redis, prefix: 'rl:' }),
});
If you pass store: 'redis://...', RateLimiter creates and owns the Redis client; call await limiter.close() during shutdown. When you pass your own Redis client to RedisStore, that client remains caller-owned unless you set ownsClient: true.
CacheHubStore keeps flex-rate-limit as the algorithm and middleware layer while delegating high-concurrency state updates to cache-hub atomic primitives. Pass a Redis client for distributed production usage; omit the client only when an in-memory cache-hub backend is acceptable. The in-memory cache-hub path prunes expired rate-limit state automatically, and await limiter.close() closes store-owned cleanup timers or cache resources.
const Redis = require('ioredis');
const { RateLimiter, CacheHubStore } = require('flex-rate-limit');
const redis = new Redis(process.env.REDIS_URL || 'redis://127.0.0.1:6379');
const limiter = new RateLimiter({
algorithm: 'sliding-window',
windowMs: 60 * 1000,
max: 100,
store: new CacheHubStore({ client: redis, prefix: 'rl:' }),
});
Read more in the storage guide.
| Algorithm | Best For | Notes |
|---|---|---|
sliding-window | Precise rolling limits | Default algorithm; stores more per-key state |
fixed-window | High-throughput coarse windows | Fast, but requests can cluster around window boundaries |
token-bucket | Controlled bursts | Allows bursts up to capacity and refills over time |
leaky-bucket | Smoothing traffic | Drains at a steady rate |
Choose semantics first, then optimize storage and hot paths. See algorithm comparison and deep analysis.
const limiter = new RateLimiter({
windowMs: 60 * 1000,
max: 100,
algorithm: 'sliding-window',
headers: true,
keyGenerator: (req) => `user:${req.user?.id || req.ip}:${req.path}`,
skip: (req) => req.path === '/health',
handler: (req, res) => {
res.status(429).json({ error: 'Too Many Requests' });
},
perRoute: {
'/api/login': { max: 5, windowMs: 15 * 60 * 1000 },
'/api/users': { max: 100, windowMs: 60 * 1000 },
},
});
| Option | Default | Description |
|---|---|---|
windowMs | 60000 | Time window in milliseconds |
max | 100 | Max requests per window; may be a function |
algorithm | sliding-window | One of the four supported algorithms |
store | memory | Store instance or 'memory' |
keyGenerator | IP-based | Builds the rate-limit key from request context |
skip | () => false | Return true to bypass rate limiting |
handler | built-in 429 response | Custom over-limit handler |
headers | true | Write X-RateLimit-* and Retry-After headers |
perRoute | null | Route-specific overrides |
skipSuccessfulRequests | false | Roll back successful responses |
skipFailedRequests | false | Roll back failed responses |
Full details are in the configuration guide and API reference.
{
allowed: true,
limit: 100,
current: 1,
remaining: 99,
resetTime: 1767225600000,
retryAfter: 0
}
The repository includes reproducible local benchmark scripts for Memory direct checks, Redis direct checks, and HTTP middleware scenarios.
Run these from a cloned repository after installing development dependencies:
npm install
npm run benchmark:memory
npm run benchmark:redis
npm run benchmark:http
The npm runtime package does not require benchmark dependencies. Redis and HTTP benchmark output records the Node.js version, Redis URL, key distribution, concurrency, and other parameters. Use BENCH_JSON=1 when you need machine-readable output.
See Benchmark and Performance for commands, environment variables, and interpretation notes.
| Entry | Description |
|---|---|
| Documentation index | English documentation navigation |
| Chinese documentation | Simplified Chinese documentation navigation |
| Quickstart | First integration path and framework examples |
| Configuration | Complete option reference and practical presets |
| Storage | Memory, Redis, and CacheHubStore selection |
| Business lock guide | User + route scoped rate limiting |
| Algorithm comparison | Choosing the right algorithm |
| API reference | Classes, options, stores, and exports |
| Benchmark guide | Local benchmark commands and caveats |
The website is built with Rspress and reuses the docs/ directory:
npm run docs:dev
npm run docs:validate
npm run docs:build
Runnable examples are available on GitHub:
| Category | Files |
|---|---|
| Quickstart | quickstart-express.js, quickstart-koa.js, quickstart-egg.js, quickstart-hapi.js, quickstart-fastify.js |
| Router examples | express-router-example.js, koa-router-example.js, egg-router-example.js, fastify-router-example.js |
| IP whitelist examples | express-ip-whitelist-independent.js, koa-ip-whitelist-independent.js, ip-whitelist-example.js |
| Standalone usage | standalone-example.js |
| Business lock | egg-business-lock-example.js |
npm test
npm run test:unit
npm run test:integration
npm run typecheck
npm run lint
npm run coverage
RedisStore or CacheHubStore with a Redis client instead of the default Memory store.REDIS_URL / BENCH_REDIS_URL.ioredis.await limiter.close() when using store: 'redis://...', or pass ownsClient: true to RedisStore if the store should close your client.check() directly and wrap the result in the framework's native middleware or hook style.FAQs
Universal rate limiting module for Node.js - supports any framework, multiple storage backends, flexible algorithms
The npm package flex-rate-limit receives a total of 41 weekly downloads. As such, flex-rate-limit popularity was classified as not popular.
We found that flex-rate-limit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Research
/Security News
Socket found 16 malicious Firefox extensions designed to steal crypto wallet recovery phrases and private keys using cloned Rabby and OKX interfaces.

Product
Socket now scans VS Code extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.

Research
/Security News
Socket uncovered two malicious VS Code themes in a GlassWorm-linked cluster with thousands of installs across VS Code Marketplace and Open VSX.