@tumull/shield
v1.2.0
Published
Drop-in API rate limiting & DDoS protection for Node.js/Next.js
Maintainers
Readme
@tumull/shield
Rate limiting, bot detection, and brute force protection for Node.js apps. Works with Next.js, Express, Fastify, Hono, or plain http. No external dependencies in the core.
Why?
Most rate limiting libs are either too simple (fixed window, no bot detection) or tied to a paid service. Shield gives you sliding window, token bucket, bot detection, brute force protection, and per-route config — all in one package, for free, with zero lock-in.
Install
npm install @tumull/shieldUsage
Next.js
// middleware.ts
import { shield } from '@tumull/shield'
export default shield({
limit: 100,
window: '1m',
})
export const config = {
matcher: '/api/:path*',
}That's basically it. Your API routes are rate-limited now.
Express
import express from 'express'
import { shieldExpress } from '@tumull/shield'
const app = express()
app.use(shieldExpress({ limit: 100, window: '1m' }))Fastify
import Fastify from 'fastify'
import { shieldFastify } from '@tumull/shield'
const app = Fastify()
app.register(shieldFastify, { limit: 100, window: '1m' })Hono
import { Hono } from 'hono'
import { shieldHono } from '@tumull/shield'
const app = new Hono()
app.use('*', shieldHono({ limit: 100, window: '1m' }))Node.js HTTP
import http from 'node:http'
import { shieldNode } from '@tumull/shield'
const limiter = shieldNode({ limit: 100, window: '1m' })
http
.createServer(async (req, res) => {
if (await limiter(req, res)) return // blocked
res.writeHead(200)
res.end('ok')
})
.listen(3000)Config
shield({
limit: 100, // requests per window
window: '1m', // "30s", "1m", "5m", "1h", "1d"
block: '15m', // how long to block after exceeding limit
algorithm: 'sliding-window', // or 'fixed-window', 'token-bucket'
// different limits for different routes
routes: {
'/api/auth/login': { limit: 5, window: '5m', block: '30m' },
'/api/public/*': { limit: 500, window: '1m' },
'/api/private/*': { allowlistGeo: ['US', 'CA'] },
'/api/webhook/*': { skip: true },
},
// custom key (default: client IP)
key: (req) => req.headers.get('x-api-key') ?? extractIP(req),
store: 'memory', // default. also supports Redis, Upstash
botDetection: true,
blockBots: ['scrapy', 'curl'],
allowlist: ['127.0.0.1'],
// country-level controls (ISO codes)
allowlistGeo: ['US', 'CA'],
blocklistGeo: ['RU'],
wafEnabled: true,
wafRules: [
{ target: 'query', operator: 'regex', value: 'union\\s*select', flags: 'i' },
{ target: 'path', value: '/admin' },
],
blocklist: [],
headers: true, // X-RateLimit-* headers
onLimit: (req, retryAfter) =>
new Response(JSON.stringify({ error: 'Slow down' }), { status: 429 }),
})Full config reference → docs/configuration.md
Stores
Memory (default) — no setup, works everywhere. LRU eviction keeps memory bounded.
import { shield, MemoryStore } from '@tumull/shield'
shield({ store: new MemoryStore({ maxSize: 10_000 }) })Redis — for multi-instance / production setups.
import { RedisStore } from '@tumull/shield/stores/redis'
import Redis from 'ioredis'
shield({ store: new RedisStore({ client: new Redis(process.env.REDIS_URL) }) })Upstash — HTTP-based, works on the edge (Vercel Edge, Cloudflare Workers).
import { UpstashStore } from '@tumull/shield/stores/upstash'
shield({
store: new UpstashStore({
url: process.env.UPSTASH_REDIS_URL!,
token: process.env.UPSTASH_REDIS_TOKEN!,
}),
})More details → docs/stores.md
Algorithms
| Algorithm | What it does | Good for |
| ---------------- | --------------------------------------------- | ------------------- |
| sliding-window | Weighted average of current + previous window | Most apps (default) |
| fixed-window | Simple counter, resets on interval | High throughput |
| token-bucket | Tokens refill at constant rate | Bursty traffic |
More details → docs/algorithms.md
Response headers
When headers: true (default):
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1708934400When blocked → 429 Too Many Requests with Retry-After header.
How it compares
| | Shield | express-rate-limit | @upstash/ratelimit | Arcjet | | ------------------ | ------ | ------------------ | ------------------ | -------- | | Next.js middleware | ✅ | ❌ | ✅ | ✅ | | Edge runtime | ✅ | ❌ | ✅ | ✅ | | Zero deps | ✅ | ✅ | ❌ | ❌ | | Sliding window | ✅ | ❌ | ✅ | ✅ | | Bot detection | ✅ | ❌ | ❌ | ✅ | | Brute force | ✅ | ❌ | ❌ | ✅ | | Per-route config | ✅ | manual | ❌ | ✅ | | Free | ✅ | ✅ | freemium | freemium |
Docs
- Getting started
- Configuration
- Algorithms
- Stores
- Framework guides
- Bot detection
- Brute force protection
- Migration from other libs
Contributing
See CONTRIBUTING.md.
License
MIT — TUMULL I.N.C.
