limiter.js
v1.0.5
Published
limiter.js is a Node.js/TypeScript library that provides simple Rate limiter protection for Express applications. It tracks requests per IP address and enforces rate limits within a sliding time window. If an IP exceeds the allowed requests, limiter.js ca
Downloads
19
Maintainers
Readme
Limiter.js
limiter.js is a Node.js/TypeScript library that provides simple Rate limiter protection for Express applications. It tracks requests per IP address and enforces rate limits within a sliding time window. If an IP exceeds the allowed requests, limiter.js can temporarily ban that IP and even permanently ban repeat offenders based on configurable thresholds. The core component is the Detector class (see src/core/Detector.ts in source) which maintains a map of IP trackers and applies a RateLimiter policy. You integrate it as an Express middleware, where it inspects each incoming request and blocks excess traffic, returning HTTP 429 when limits are exceeded.
Features
- IP-based rate limiting: Counts requests per IP in a configurable time window (
windowMs). - Temporary bans: Automatically bans an IP for
banDurationMsonce it exceedsmaxHitsAllowedwithin the window. - Permanent bans: If an IP repeatedly exceeds limits (meeting
permanentBanThreshold), it can be permanently banned. - Express middleware: Integrates easily via
expressGuardMiddleware(detector) in any Express app. - Logging of IP status: Provides methods to log current hit counts and ban status for each tracked IP to the console (useful for monitoring).
- Configurable: All thresholds (time window, max hits, ban duration, etc.) are adjustable through a simple
Configobject.
Installation
You can install the library using npm:
npm install limiter.js@latestQuick Start
import { expressGuardMiddleware, Detector } from "limiter.js";
import express from "express";
const app = express();
const port = 3000;
const detector = new Detector({
windowMs: 60 * 1000, // 1 minute time window
maxHitsAllowed: 10, // 10 requests per minute
banDurationMs: 10 * 1000, // 10 seconds ban duration
permanentBanThreshold: 30, // 30 requests for permanent ban
});
app.use(expressGuardMiddleware(detector));
app.get("/", (req, res) => {
res.send("Hello, world!");
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});Configuration Examples
Basic API Rate Limiting
// Basic setup for a public API - allows 100 requests per hour
const apiDetector = new Detector({
windowMs: 60 * 60 * 1000, // 1 hour
maxHitsAllowed: 100,
banDurationMs: 30 * 60 * 1000, // 30 minutes ban
permanentBanThreshold: 500, // Permanent ban after 500 requests in window
});
app.use('/api', expressGuardMiddleware(apiDetector));Strict Authentication Endpoint Protection
// Strict limits for sensitive endpoints like login
const authDetector = new Detector({
windowMs: 15 * 60 * 1000, // 15 minutes
maxHitsAllowed: 5, // Only 5 login attempts per 15 minutes
banDurationMs: 60 * 60 * 1000, // 1 hour ban
permanentBanThreshold: 20, // Permanent ban after 20 attempts
});
app.use('/auth/login', expressGuardMiddleware(authDetector));
app.use('/auth/register', expressGuardMiddleware(authDetector));Development Mode (Lenient)
// Lenient settings for development environment
const devDetector = new Detector({
windowMs: 60 * 1000, // 1 minute
maxHitsAllowed: 1000, // Very high limit for development
banDurationMs: 5 * 1000, // Short 5-second ban
// No permanent ban threshold for development
});
if (process.env.NODE_ENV === 'development') {
app.use(expressGuardMiddleware(devDetector));
}Production Web App
// Balanced settings for a production web application
const webDetector = new Detector({
windowMs: 10 * 60 * 1000, // 10 minutes
maxHitsAllowed: 200, // 200 requests per 10 minutes
banDurationMs: 20 * 60 * 1000, // 20 minutes ban
permanentBanThreshold: 1000, // Permanent ban threshold
});
app.use(expressGuardMiddleware(webDetector));Advanced Usage
Multiple Rate Limiters for Different Routes
import { expressGuardMiddleware, Detector } from "limiter.js";
import express from "express";
const app = express();
// General API rate limiter
const generalDetector = new Detector({
windowMs: 60 * 1000,
maxHitsAllowed: 60,
banDurationMs: 60 * 1000,
permanentBanThreshold: 300,
});
// Strict rate limiter for sensitive operations
const strictDetector = new Detector({
windowMs: 5 * 60 * 1000,
maxHitsAllowed: 10,
banDurationMs: 30 * 60 * 1000,
permanentBanThreshold: 50,
});
// File upload rate limiter
const uploadDetector = new Detector({
windowMs: 60 * 1000,
maxHitsAllowed: 5,
banDurationMs: 10 * 60 * 1000,
permanentBanThreshold: 20,
});
// Apply different limiters to different routes
app.use('/api/general', expressGuardMiddleware(generalDetector));
app.use('/api/auth', expressGuardMiddleware(strictDetector));
app.use('/api/upload', expressGuardMiddleware(uploadDetector));
app.get('/api/general/users', (req, res) => {
res.json({ users: [] });
});
app.post('/api/auth/login', (req, res) => {
res.json({ token: 'example-token' });
});
app.post('/api/upload', (req, res) => {
res.json({ message: 'File uploaded successfully' });
});
app.listen(3000, () => {
console.log('Server running with multiple rate limiters');
});Monitoring and Logging
import { expressGuardMiddleware, Detector } from "limiter.js";
import express from "express";
const app = express();
const detector = new Detector({
windowMs: 60 * 1000,
maxHitsAllowed: 100,
banDurationMs: 5 * 60 * 1000,
permanentBanThreshold: 500,
});
app.use(expressGuardMiddleware(detector));
// Monitoring endpoint (protect this in production!)
app.get('/admin/rate-limit-status', (req, res) => {
console.log('=== Rate Limiter Status ===');
detector.logStatus(); // Logs all tracked IPs
res.json({ message: 'Check console for rate limiter status' });
});
// Check specific IP status
app.get('/admin/ip-status/:ip', (req, res) => {
const ip = req.params.ip;
console.log(`=== Status for IP: ${ip} ===`);
detector.logIPStatus(ip);
res.json({ message: `Check console for IP ${ip} status` });
});
// Periodic logging (every 5 minutes)
setInterval(() => {
console.log('=== Periodic Rate Limiter Status ===');
detector.logStatus();
}, 5 * 60 * 1000);
app.listen(3000);Custom Error Handling
import { expressGuardMiddleware, Detector } from "limiter.js";
import express from "express";
const app = express();
const detector = new Detector({
windowMs: 60 * 1000,
maxHitsAllowed: 50,
banDurationMs: 10 * 60 * 1000,
permanentBanThreshold: 200,
});
// Custom middleware that adds additional handling
app.use((req, res, next) => {
const result = detector.handleRequest(req.ip || req.connection.remoteAddress || 'unknown');
if (result.blocked) {
// Log the blocked request
console.log(`Blocked request from ${req.ip}: ${result.reason}`);
// Custom response based on ban type
if (result.reason?.includes('permanently banned')) {
return res.status(429).json({
error: 'Permanently Banned',
message: 'Your IP has been permanently banned due to repeated violations.',
retryAfter: null
});
} else {
return res.status(429).json({
error: 'Rate Limited',
message: 'Too many requests. Please try again later.',
retryAfter: '10 minutes'
});
}
}
next();
});
app.get('/', (req, res) => {
res.json({ message: 'API is working!' });
});
app.listen(3000);Environment-based Configuration
import { expressGuardMiddleware, Detector } from "limiter.js";
import express from "express";
const app = express();
// Configuration based on environment
const getDetectorConfig = () => {
const env = process.env.NODE_ENV || 'development';
switch (env) {
case 'production':
return {
windowMs: 15 * 60 * 1000, // 15 minutes
maxHitsAllowed: 100,
banDurationMs: 60 * 60 * 1000, // 1 hour
permanentBanThreshold: 500,
};
case 'staging':
return {
windowMs: 5 * 60 * 1000, // 5 minutes
maxHitsAllowed: 200,
banDurationMs: 30 * 60 * 1000, // 30 minutes
permanentBanThreshold: 1000,
};
case 'development':
default:
return {
windowMs: 60 * 1000, // 1 minute
maxHitsAllowed: 1000,
banDurationMs: 10 * 1000, // 10 seconds
permanentBanThreshold: 5000,
};
}
};
const detector = new Detector(getDetectorConfig());
app.use(expressGuardMiddleware(detector));
app.get('/', (req, res) => {
res.json({
message: `Hello from ${process.env.NODE_ENV} environment!`,
rateLimitConfig: getDetectorConfig()
});
});
app.listen(3000, () => {
console.log(`Server running in ${process.env.NODE_ENV} mode`);
});Integration with Express Router
import { expressGuardMiddleware, Detector } from "limiter.js";
import express from "express";
const app = express();
const router = express.Router();
// Create different detectors for different route groups
const publicApiDetector = new Detector({
windowMs: 60 * 1000,
maxHitsAllowed: 100,
banDurationMs: 5 * 60 * 1000,
permanentBanThreshold: 500,
});
const adminApiDetector = new Detector({
windowMs: 60 * 1000,
maxHitsAllowed: 20,
banDurationMs: 30 * 60 * 1000,
permanentBanThreshold: 100,
});
// Public API routes with generous limits
router.use('/public', expressGuardMiddleware(publicApiDetector));
router.get('/public/status', (req, res) => {
res.json({ status: 'OK', timestamp: new Date() });
});
router.get('/public/info', (req, res) => {
res.json({ info: 'This is a public endpoint' });
});
// Admin routes with strict limits
router.use('/admin', expressGuardMiddleware(adminApiDetector));
router.get('/admin/users', (req, res) => {
res.json({ users: ['admin', 'user1', 'user2'] });
});
router.post('/admin/settings', (req, res) => {
res.json({ message: 'Settings updated' });
});
app.use('/api', router);
app.listen(3000, () => {
console.log('Server running with route-specific rate limiting');
});Configuration Reference
The Detector is configured via an object with the following properties:
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| windowMs | number | Yes | Time window for counting requests, in milliseconds |
| maxHitsAllowed | number | Yes | Maximum allowed requests per IP within one window |
| banDurationMs | number | Yes | Duration of a temporary ban (in ms) when the rate is exceeded |
| permanentBanThreshold | number | No | If provided, an IP reaching this hit count in the window will be permanently banned |
Common Configuration Patterns
- Lenient (Development):
windowMs: 60000, maxHitsAllowed: 1000, banDurationMs: 5000 - Moderate (Web App):
windowMs: 600000, maxHitsAllowed: 200, banDurationMs: 1200000 - Strict (API):
windowMs: 3600000, maxHitsAllowed: 100, banDurationMs: 1800000 - Very Strict (Auth):
windowMs: 900000, maxHitsAllowed: 5, banDurationMs: 3600000
API Methods
Detector Methods
handleRequest(ip: string): Manually check if an IP should be blockedlogStatus(): Log status of all tracked IPs to consolelogIPStatus(ip: string): Log status of a specific IP to console
Best Practices
- Environment-specific configs: Use different limits for development, staging, and production
- Route-specific limits: Apply stricter limits to sensitive endpoints (auth, admin)
- Monitor regularly: Use the logging methods to monitor rate limiting effectiveness
- Gradual enforcement: Start with lenient limits and tighten based on traffic patterns
- Consider user experience: Don't make limits too strict for legitimate users
- Permanent ban carefully: Use permanent bans sparingly and only for clear abuse patterns
Contributing
Contributions, bug reports, and feature requests are welcome! Please fork the repository and open an issue or pull request on GitHub. Ensure your code follows the existing style and includes any relevant tests.
License
This project is licensed under the ISC License.
