On this page

Hono Adapter

The Hono adapter provides seamless integration with Hono applications using the official createMiddleware pattern.

Installation

npm install @joint-ops/hitlimit hono
# or: pnpm add @joint-ops/hitlimit hono
bun add @joint-ops/hitlimit-bun hono

Basic Usage

Use hitlimit as Hono middleware:

app.ts
import { Hono } from 'hono'
import { serve } from '@hono/node-server'
import { hitlimit } from '@joint-ops/hitlimit/hono'

const app = new Hono()

// Apply to all routes
app.use(hitlimit({
  limit: 100,
  window: '1m'
}))

app.get('/', (c) => c.text('Hello World'))

serve({ fetch: app.fetch, port: 3000 })
app.ts
import { Hono } from 'hono'
import { hitlimit } from '@joint-ops/hitlimit-bun/hono'

const app = new Hono()

// Apply to all routes
app.use(hitlimit({
  limit: 100,
  window: '1m'
}))

app.get('/', (c) => c.text('Hello Bun + Hono!'))

Bun.serve({ port: 3000, fetch: app.fetch })

Route-Specific Rate Limiting

Apply different limits to specific routes:

const app = new Hono()

// Public routes
app.get('/', (c) => c.text('Welcome'))

// Strict limit for auth routes
const auth = new Hono()
auth.use(hitlimit({ limit: 5, window: '15m' }))
auth.post('/login', (c) => c.json({ success: true }))
auth.post('/register', (c) => c.json({ success: true }))

// Higher limit for API routes
const api = new Hono()
api.use(hitlimit({ limit: 1000, window: '1m' }))
api.get('/users', (c) => c.json([]))
api.get('/posts', (c) => c.json([]))

app.route('/auth', auth)
app.route('/api', api)

Custom Key Extraction

Rate limit by user ID, API key, or custom identifiers:

app.use(hitlimit({
  limit: 100,
  window: '1m',
  key: (c) => {
    // Rate limit by custom header
    return c.req.header('x-api-key') || 'anonymous'
  }
}))

Tiered Limits

Apply different limits based on user plan or tier:

app.use(hitlimit({
  tiers: {
    free: { limit: 10, window: '1m' },
    pro: { limit: 100, window: '1m' },
    enterprise: { limit: Infinity }
  },
  tier: (c) => {
    return c.req.header('x-plan') || 'free'
  }
}))

Skipping Requests

Bypass rate limiting for certain requests:

hitlimit({
  limit: 100,
  window: '1m',
  skip: (c) => {
    // Skip health checks and internal requests
    return c.req.path === '/health' ||
           c.req.header('x-internal') === 'true'
  }
})

Custom Error Response

Customize the response when rate limit is exceeded:

hitlimit({
  limit: 100,
  window: '1m',
  response: (info) => ({
    error: 'RATE_LIMIT_EXCEEDED',
    message: `Too many requests. Try again in ${info.resetIn} seconds.`,
    retryAfter: info.resetIn
  })
})

Using with Stores

Use Redis or SQLite for distributed rate limiting:

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

app.use(hitlimit({
  limit: 100,
  window: '1m',
  store: redisStore({
    url: 'redis://localhost:6379'
  })
}))
import { hitlimit } from '@joint-ops/hitlimit-bun/hono'
import { sqliteStore } from '@joint-ops/hitlimit-bun/stores/sqlite'

app.use(hitlimit({
  limit: 100,
  window: '1m',
  store: sqliteStore({
    path: './rate-limits.db'
  })
}))

Migrating from hono-rate-limiter

If you're coming from hono-rate-limiter, hitlimit offers a similar API with more features:

Before (hono-rate-limiter)
import { rateLimiter } from 'hono-rate-limiter'

app.use(rateLimiter({
  windowMs: 60000, // milliseconds
  limit: 100,
  keyGenerator: (c) => c.req.header('x-api-key')
}))
After (hitlimit)
app.use(hitlimit({
  window: '1m', // human-readable!
  limit: 100,
  key: (c) => c.req.header('x-api-key') || 'anonymous'
}))

Key improvements:

  • Human-readable time windows'1m' instead of milliseconds
  • Built-in tiered limits — No manual tier management needed
  • Zero runtime dependencies — no external packages needed
  • More stores — Memory, SQLite, Redis built-in (no separate packages)
  • Better TypeScript — Full type inference for all options