API Reference
Complete API documentation
Ratelimit
The main class for rate limiting.
Constructor
new Ratelimit(config: RatelimitConfig)RatelimitConfig
| Property | Type | Required | Description |
|---|---|---|---|
redis | RedisClient | No* | Bun Redis client instance |
adapter | RedisAdapter | No* | Custom Redis adapter |
limiter | Algorithm | Yes | Rate limiting algorithm |
prefix | string | No | Key prefix (default: "ratelimit") |
analytics | boolean | No | Enable analytics (default: false) |
onLimitExceeded | Function | No | Callback when limit exceeded |
*Either redis or adapter must be provided.
Example
const ratelimit = new Ratelimit({
redis: new RedisClient(),
limiter: fixedWindow(10, 60),
prefix: 'api',
analytics: true,
onLimitExceeded: async (identifier, response) => {
console.log(`Limit exceeded for ${identifier}`)
},
})Methods
limit()
Rate limit a single identifier.
limit(identifier: string): Promise<RatelimitResponse>Parameters:
identifier- Unique identifier (user ID, IP address, API key, etc.)
Returns:
interface RatelimitResponse {
success: boolean // Whether request is allowed
limit: number // Maximum requests allowed
remaining: number // Requests remaining
reset: number // Timestamp when limit resets (ms)
pending: Promise<unknown> // Internal promise
}Example:
const { success, remaining, reset } = await ratelimit.limit('user-123')
if (!success) {
throw new Error(`Rate limit exceeded. Try again at ${new Date(reset)}`)
}multiLimit()
Rate limit multiple identifiers at once.
multiLimit(identifiers: string[]): Promise<MultiRatelimitResponse[]>Parameters:
identifiers- Array of unique identifiers
Returns:
interface MultiRatelimitResponse {
identifier: string // The identifier
success: boolean // Whether request is allowed
limit: number // Maximum requests allowed
remaining: number // Requests remaining
reset: number // Timestamp when limit resets (ms)
}Example:
const results = await ratelimit.multiLimit(['user-1', 'user-2', 'user-3'])
for (const result of results) {
console.log(`${result.identifier}: ${result.success ? 'allowed' : 'denied'}`)
}reset()
Reset rate limit for an identifier.
reset(identifier: string): Promise<void>Parameters:
identifier- Identifier to reset
Example:
await ratelimit.reset('user-123')getRemaining()
Get remaining requests for an identifier.
getRemaining(identifier: string): Promise<number>Parameters:
identifier- Identifier to check
Returns:
- Number of remaining requests
Example:
const remaining = await ratelimit.getRemaining('user-123')
console.log(`${remaining} requests remaining`)getAnalytics()
Get analytics for an identifier (requires analytics: true).
getAnalytics(identifier: string): Promise<{ allowed: number; denied: number } | null>Parameters:
identifier- Identifier to get analytics for
Returns:
- Object with
allowedanddeniedcounts, ornullif analytics disabled
Example:
const stats = await ratelimit.getAnalytics('user-123')
if (stats) {
console.log(`Allowed: ${stats.allowed}, Denied: ${stats.denied}`)
}Algorithm Presets
fixedWindow()
Create a fixed window algorithm.
fixedWindow(limit: number, window: number): AlgorithmParameters:
limit- Maximum number of requestswindow- Time window in seconds
Example:
const limiter = fixedWindow(10, 60) // 10 requests per 60 secondsslidingWindow()
Create a sliding window algorithm.
slidingWindow(limit: number, window: number): AlgorithmParameters:
limit- Maximum number of requestswindow- Time window in seconds
Example:
const limiter = slidingWindow(10, 60) // 10 requests per 60 secondstokenBucket()
Create a token bucket algorithm.
tokenBucket(limit: number, window: number, refillRate?: number): AlgorithmParameters:
limit- Maximum number of tokenswindow- Time window in secondsrefillRate- Tokens per second (default:limit / window)
Example:
const limiter = tokenBucket(10, 60, 0.5) // 10 tokens, refills at 0.5/secAdapters
BunRedisAdapter
Adapter for Bun's native Redis client.
new BunRedisAdapter(client: RedisClient)Example:
import { RedisClient } from 'bun'
import { BunRedisAdapter } from 'bunlimit'
const redis = new RedisClient('redis://localhost:6379')
const adapter = new BunRedisAdapter(redis)IoRedisAdapter
Adapter for ioredis.
new IoRedisAdapter(client: Redis)Example:
import Redis from 'ioredis'
import { IoRedisAdapter } from 'bunlimit'
const redis = new Redis()
const adapter = new IoRedisAdapter(redis)NodeRedisAdapter
Adapter for node-redis (v4+).
new NodeRedisAdapter(client: RedisClientType)Example:
import { createClient } from 'redis'
import { NodeRedisAdapter } from 'bunlimit'
const redis = createClient()
await redis.connect()
const adapter = new NodeRedisAdapter(redis)DenoKvAdapter
Adapter for Deno KV.
new DenoKvAdapter(kv: Deno.Kv)Example:
import { openKv } from '@deno/kv'
import { DenoKvAdapter } from 'bunlimit'
const kv = await openKv('http://localhost:4512')
const adapter = new DenoKvAdapter(kv)Types
RedisAdapter
Interface for creating custom adapters.
interface RedisAdapter {
incr(key: string): Promise<number>
get(key: string): Promise<string | null>
set(key: string, value: string): Promise<void>
expire(key: string, seconds: number): Promise<void>
del(...keys: string[]): Promise<void>
keys(pattern: string): Promise<string[]>
hincrby(key: string, field: string, increment: number): Promise<number>
hmget(key: string, fields: string[]): Promise<(string | null)[]>
hmset(key: string, data: string[]): Promise<void>
}Algorithm
Rate limiting algorithm configuration.
interface Algorithm {
type: 'fixed-window' | 'sliding-window' | 'token-bucket'
limit: number
window: number
refillRate?: number // Only for token-bucket
}Callbacks
onLimitExceeded
Callback function triggered when rate limit is exceeded.
type OnLimitExceeded = (identifier: string, response: RatelimitResponse) => void | Promise<void>Example:
const callback: OnLimitExceeded = async (identifier, response) => {
console.log(`Rate limit exceeded for ${identifier}`)
console.log(`Reset at: ${new Date(response.reset)}`)
await sendNotification(identifier)
}Error Handling
Common Errors
Missing Redis Configuration
// ❌ Error: Either adapter or redis must be provided
new Ratelimit({
limiter: fixedWindow(10, 60),
})// ✅ Correct
new Ratelimit({
redis: new RedisClient(),
limiter: fixedWindow(10, 60),
})Connection Errors
try {
const result = await ratelimit.limit('user-123')
} catch (error) {
if (error.code === 'ERR_REDIS_CONNECTION_CLOSED') {
console.error('Redis connection closed')
} else {
console.error('Unexpected error:', error)
}
}TypeScript
bunlimit is written in TypeScript and provides full type definitions.
Import Types
import type { RatelimitConfig, RatelimitResponse, MultiRatelimitResponse, Algorithm, RedisAdapter } from 'bunlimit'Type-Safe Configuration
const config: RatelimitConfig = {
redis: new RedisClient(),
limiter: fixedWindow(10, 60),
prefix: 'api',
analytics: true,
onLimitExceeded: async (identifier, response) => {
// TypeScript knows the types here
console.log(identifier.toUpperCase())
console.log(response.reset.toFixed(0))
},
}
const ratelimit = new Ratelimit(config)Custom Adapter with Types
import type { RedisAdapter } from 'bunlimit'
class MyAdapter implements RedisAdapter {
async incr(key: string): Promise<number> {
// Implementation
return 1
}
// ... implement other methods
}