A dependency-free Node.js rate limiter you can add to almost any project. It includes:
- a portable
check()API for any Node.js source code - Express-style middleware
- an in-memory token bucket store
- a small store interface so you can add Redis, database, or shared cache storage later
npm install portable-rate-limitFor local testing before publishing:
npm install ../path/to/portable-rate-limitconst { createRateLimiter } = require('portable-rate-limit');
const limiter = createRateLimiter({
limit: 10,
windowMs: 60_000
});
async function handleLogin(userId) {
const result = await limiter.check({ key: `login:${userId}` });
if (!result.allowed) {
throw new Error(`Try again in ${Math.ceil(result.retryAfterMs / 1000)} seconds`);
}
return doLogin(userId);
}const express = require('express');
const { expressRateLimit } = require('portable-rate-limit');
const app = express();
app.use(expressRateLimit({
limit: 100,
windowMs: 15 * 60 * 1000,
keyGenerator: ({ req }) => req.ip
}));
app.get('/', (req, res) => {
res.json({ ok: true });
});When a request is blocked, the middleware returns HTTP 429 and sets:
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-ResetRetry-After
createRateLimiter({
limit: 60, // max tokens in the bucket
windowMs: 60_000, // time to fully refill the bucket
keyGenerator: ({ req, key }) => key || req.ip,
skip: ({ req }) => false,
onLimit: (input, result) => {},
store: customStore
});The default store is in memory. That is fine for one Node.js process. For multiple servers or serverless deployments, provide a shared store backed by Redis or a database.
const store = {
async get(key) {
return bucket;
},
async set(key, bucket) {
// bucket = { tokens, updatedAt, expiresAt }
},
async delete(key) {}
};npm test- Create an npm account at
https://www.npmjs.com/signup. - Choose a unique package name in
package.json. Search npm first because package names must be unique. - Log in:
npm login- Run tests:
npm test- Preview the package contents:
npm pack --dry-run- Publish:
npm publish --access publicFor later updates, change the version and publish again:
npm version patch
npm publish --access publicUse minor for new features and major for breaking changes.