Open Source · MIT License

Protect your API.
Every request.

Production-grade rate limiting middleware for Express.
3 algorithms. Redis-backed. Fail-open. Zero config to start.

3 Algorithms
27 Tests
0 Runtime Deps
server.ts
import express from 'express';
import { gatekeeper } from '@sibilsoren/gatekeeper';

const app = express();

// 100 requests/min per IP
app.use(gatekeeper());

// Strict auth limits
app.post('/auth/login', gatekeeper({
  limit: 5,
  window: '15m',
}));

app.listen(3000);
429 Too Many Requests
{
  "error": "Too Many Requests",
  "retryAfter": 30
}
Response Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 42
Retry-After: 30
Algorithms

Choose your strategy.

Three battle-tested algorithms. Pick the right one for your use case.

🪟

Fixed Window

The simplest approach. Resets the counter at each window boundary. Fast and memory-efficient.

80/100
🚫 100/100
20/100
⚡ Fastest 📦 1 counter/client
🪣

Token Bucket

Allows controlled bursts. Tokens refill at a steady rate. Perfect for API billing and throttling.

🪙 🪙 🪙 🪙 🪙 🪙
4/6 tokens · refills 2/sec
💰 Great for billing 🔀 Variable cost
Usage

From zero to protected in 30 seconds.

01

Install

npm install @sibilsoren/gatekeeper

For Redis support, also install ioredis

02

Add middleware

import { gatekeeper } from '@sibilsoren/gatekeeper';

// That's it. Zero config works.
app.use(gatekeeper());
03

Customize per route

// Strict for auth
app.post('/auth', gatekeeper({
  limit: 5, window: '15m'
}));

// Generous for reads
app.use('/api', gatekeeper({
  limit: 1000, window: '1m'
}));
04

Scale with Redis

import { RedisStore } from '@sibilsoren/gatekeeper';
import Redis from 'ioredis';

app.use(gatekeeper({
  store: new RedisStore(new Redis()),
}));
Why Gatekeeper

Built for production. Not for demos.

🛡️
Fail-Open

Redis down? Requests still flow. Your API stays up.

⚛️
Atomic Operations

Lua scripts in Redis prevent race conditions. No double-counting.

📊
Standard Headers

X-RateLimit-Limit, Remaining, Reset, and Retry-After on every response.

🎯
Flexible Keys

Rate limit by IP, API key, user ID, or any custom function.

🪶
Zero Dependencies

No runtime deps. ioredis is an optional peer dependency.

📦
Dual ESM + CJS

Works everywhere. TypeScript types included.

Configuration

Every knob you need.

Option Type Default Description
limitnumber100Max requests per window
windowstring | number"1m"Window size ("30s", "5m", "1h", or ms)
algorithmstring"sliding-window""fixed-window" | "sliding-window" | "token-bucket"
storeStoreMemoryStoreStorage backend (MemoryStore or RedisStore)
keyGeneratorfunctionreq.ipGenerate rate limit key from request
skipfunction() => falseSkip rate limiting for certain requests
messagestring"Too Many Requests"Custom error message
headersbooleantrueInclude X-RateLimit-* headers
capacitynumber100Token bucket capacity
refillRatenumber10Tokens per second (token bucket)

Your API deserves better
than express-rate-limit.

Distributed. Atomic. Fail-open. Production-ready.

npm install @sibilsoren/gatekeeper