app.use(hitlimit({ limit: 100, window: '1m' }))
Same API everywhere. Express, Fastify, Hono, NestJS, Bun.serve, Elysia. No adapters to install. No framework-specific config. Just one package and you are done.
Every Framework, Same Code
// Express
import { hitlimit } from '@joint-ops/hitlimit'
app.use(hitlimit({ limit: 100, window: '1m' }))
// Fastify
import { hitlimit } from '@joint-ops/hitlimit/fastify'
await app.register(hitlimit, { limit: 100, window: '1m' })
// Hono
import { hitlimit } from '@joint-ops/hitlimit/hono'
app.use(hitlimit({ limit: 100, window: '1m' }))
// NestJS
import { HitLimitModule, HitLimitGuard } from '@joint-ops/hitlimit/nest'
@Module({
imports: [HitLimitModule.register({ limit: 100, window: '1m' })],
providers: [{ provide: APP_GUARD, useClass: HitLimitGuard }]
})
export class AppModule {}
// Bun.serve
import { hitlimit } from '@joint-ops/hitlimit-bun'
Bun.serve({ fetch: hitlimit({ limit: 100, window: '1m' }, handler) })
// Elysia
import { hitlimit } from '@joint-ops/hitlimit-bun/elysia'
new Elysia().use(hitlimit({ limit: 100, window: '1m' })).listen(3000)
Switch frameworks tomorrow. Your rate limiting code stays the same.
4 Storage Backends Built In
No extra packages. No separate installs. Pick the right store for your deployment and swap it in one line.
// Memory (default) - fastest, no setup
app.use(hitlimit({ limit: 100, window: '1m' }))
// SQLite - survives restarts
app.use(hitlimit({ store: sqliteStore({ path: './limits.db' }), ... }))
// Redis - distributed across instances
app.use(hitlimit({ store: redisStore({ url: process.env.REDIS_URL }), ... }))
// Postgres - use your existing database
app.use(hitlimit({ store: postgresStore({ pool }), ... }))
Start with memory on day one. Move to Postgres or Redis when you scale. Nothing else changes.
New in v1.2.0: PostgreSQL Store
Most teams already have Postgres running. Why add Redis just for rate limiting?
import { postgresStore } from '@joint-ops/hitlimit/stores/postgres'
import { Pool } from 'pg'
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
app.use(hitlimit({
limit: 100,
window: '1m',
store: postgresStore({ pool })
}))
One atomic query per request. Zero race conditions. Tables created automatically on first run. Named prepared statements for 30 to 40 percent lower latency. No new infrastructure to manage.
Fast
Node.js (10K unique IPs)
Memory 3.16M ops/s 316ns
SQLite 352K ops/s 2.8us
Redis 6.7K ops/s 149us
Postgres 3.0K ops/s 336us
Bun (10K unique IPs)
Memory 8.32M ops/s 120ns
bun:sqlite 325K ops/s 3.1us
Redis 6.7K ops/s 148us
Postgres 3.7K ops/s 273us
Peak: 12.38M ops/s on Bun. 4.83M ops/s on Node.js.
All benchmarks are open source. Clone the repo and run them on your hardware.
More Than a Counter
Tiered limits for free, pro and enterprise plans.
Auto ban repeat offenders after N violations.
Group limits for per-team or per-org quotas.
Skip rules for health checks, admins, internal routes.
Human readable windows like '15m', '1h', '1d' instead of milliseconds.
All built in. All zero dependencies.
Get Started
npm install @joint-ops/hitlimit # Node.js
bun add @joint-ops/hitlimit-bun # Bun
Docs | npm | Release notes
If it saves you time give it a star.
Top comments (0)