On this page

Store API

Using Bun? See the Bun Stores API for @joint-ops/hitlimit-bun.

Stores manage rate limit data persistence. All stores implement the HitLimitStore interface.

Store Interface

interface HitLimitStore {
  hit(key: string, windowMs: number, limit: number): Promise<StoreResult> | StoreResult
  reset(key: string): Promise<void> | void
  shutdown?(): Promise<void> | void
}

interface StoreResult {
  count: number
  resetAt: number
}

Methods

hit(key, windowMs, limit)

Increments the request count and returns updated info.

const result = await store.hit('user:123', 60000, 100)
// Returns: { count: 43, resetAt: 1640000060000 }

reset(key)

Resets the rate limit for a specific key.

await store.reset('user:123')

shutdown()

Optional cleanup method for closing connections.

await store.shutdown()

Built-in Stores

memoryStore()

In-memory storage, suitable for single-instance deployments.

import { memoryStore } from '@joint-ops/hitlimit'

const store = memoryStore()

sqliteStore()

Persistent SQLite storage for single-server deployments.

import { sqliteStore } from '@joint-ops/hitlimit/stores/sqlite'

const store = sqliteStore({
  path: './rate-limits.db'
})

redisStore()

Redis storage for distributed deployments.

import { redisStore } from '@joint-ops/hitlimit/stores/redis'

const store = redisStore({
  url: 'redis://localhost:6379',
  keyPrefix: 'rl:'
})

valkeyStore()

Valkey storage for distributed deployments. Thin wrapper over RedisStore — uses the same ioredis client and Lua scripts.

import { valkeyStore } from '@joint-ops/hitlimit/stores/valkey'

const store = valkeyStore({
  url: 'redis://localhost:6379',
  keyPrefix: 'rl:'
})

dragonflyStore()

DragonflyDB storage for high-throughput distributed deployments. Thin wrapper over RedisStore — uses the same ioredis client and Lua scripts.

import { dragonflyStore } from '@joint-ops/hitlimit/stores/dragonfly'

const store = dragonflyStore({
  url: 'redis://localhost:6379',
  keyPrefix: 'rl:'
})

postgresStore()

PostgreSQL storage for distributed deployments using your existing database.

import { postgresStore } from '@joint-ops/hitlimit/stores/postgres'
import { Pool } from 'pg'

const pool = new Pool({ connectionString: 'postgres://localhost:5432/mydb' })

const store = postgresStore({
  pool,
  tablePrefix: 'hitlimit',  // Table name prefix
  cleanupInterval: 60000    // Cleanup every 60s
})

Creating a Custom Store

import type { HitLimitStore, StoreResult } from '@joint-ops/hitlimit'

class MyStore implements HitLimitStore {
  private data = new Map<string, StoreResult>()

  hit(key: string, windowMs: number): StoreResult {
    const now = Date.now()
    const existing = this.data.get(key)

    if (existing && existing.resetAt > now) {
      existing.count++
      return existing
    }

    const result = { count: 1, resetAt: now + windowMs }
    this.data.set(key, result)
    return result
  }

  reset(key: string) {
    this.data.delete(key)
  }
}