npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@joint-ops/hitlimit-bun

v1.0.4

Published

Fast Bun-native rate limiting for Bun.serve & Elysia - API throttling with bun:sqlite, high performance request limiting

Readme

@joint-ops/hitlimit-bun

npm version npm downloads GitHub TypeScript Bun

The fastest rate limiter for Bun - Native bun:sqlite performance | Elysia rate limit plugin

hitlimit-bun is a high-performance, Bun-native rate limiting library for Bun.serve and Elysia applications. Built specifically for Bun's runtime with native bun:sqlite for maximum performance. The only rate limiter designed from the ground up for Bun.

Documentation | GitHub | npm

⚡ Why hitlimit-bun?

hitlimit-bun uses Bun's native SQLite - no FFI overhead, no Node.js polyfills.

┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│  bun:sqlite         ████████████████████████████  520,000 ops/s │
│  better-sqlite3     ██████████████████░░░░░░░░░░  400,000 ops/s │
│                                                                 │
│  bun:sqlite is 30% faster with zero FFI overhead                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
  • Bun Native - Built specifically for Bun's runtime, not a Node.js port
  • 7.2M ops/sec - Memory store performance
  • 520K ops/sec - With bun:sqlite persistence
  • Zero Config - Works out of the box with sensible defaults
  • Elysia Plugin - First-class Elysia framework integration
  • TypeScript First - Full type safety and IntelliSense support
  • Tiny Footprint - ~23KB total, zero runtime dependencies

Installation

bun add @joint-ops/hitlimit-bun

Quick Start

Bun.serve Rate Limiting

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

Bun.serve({
  fetch: hitlimit({}, (req) => new Response('Hello!'))
})

Elysia Rate Limiting

import { Elysia } from 'elysia'
import { hitlimit } from '@joint-ops/hitlimit-bun/elysia'

new Elysia()
  .use(hitlimit({ limit: 100, window: '1m' }))
  .get('/', () => 'Hello World!')
  .listen(3000)

Using createHitLimit

import { createHitLimit } from '@joint-ops/hitlimit-bun'

const limiter = createHitLimit({ limit: 100, window: '1m' })

Bun.serve({
  async fetch(req, server) {
    // Returns a 429 Response if blocked, or null if allowed
    const blocked = await limiter.check(req, server)
    if (blocked) return blocked

    return new Response('Hello!')
  }
})

Features

API Rate Limiting

Protect your Bun APIs from abuse with high-performance rate limiting.

Bun.serve({
  fetch: hitlimit({ limit: 1000, window: '1h' }, handler)
})

Login & Authentication Protection

Prevent brute force attacks on login endpoints.

const authLimiter = createHitLimit({ limit: 5, window: '15m' })

Bun.serve({
  async fetch(req, server) {
    const url = new URL(req.url)

    if (url.pathname.startsWith('/auth')) {
      const blocked = await authLimiter.check(req, server)
      if (blocked) return blocked
    }

    return handler(req, server)
  }
})

Tiered Rate Limits

Different limits for different user tiers (free, pro, enterprise).

hitlimit({
  tiers: {
    free: { limit: 100, window: '1h' },
    pro: { limit: 5000, window: '1h' },
    enterprise: { limit: Infinity }
  },
  tier: (req) => req.headers.get('x-tier') || 'free'
}, handler)

Custom Rate Limit Keys

Rate limit by IP address, user ID, API key, or any custom identifier.

hitlimit({
  key: (req) => req.headers.get('x-api-key') || 'anonymous'
}, handler)

Elysia Route-Specific Limits

Apply different limits to different route groups in Elysia.

new Elysia()
  // Global limit
  .use(hitlimit({ limit: 100, window: '1m', name: 'global' }))

  // Stricter limit for auth
  .group('/auth', (app) =>
    app
      .use(hitlimit({ limit: 5, window: '15m', name: 'auth' }))
      .post('/login', handler)
  )

  // Higher limit for API
  .group('/api', (app) =>
    app
      .use(hitlimit({ limit: 1000, window: '1m', name: 'api' }))
      .get('/data', handler)
  )
  .listen(3000)

Configuration Options

hitlimit({
  // Basic options
  limit: 100,              // Max requests per window (default: 100)
  window: '1m',            // Time window: 30s, 15m, 1h, 1d (default: '1m')

  // Custom key extraction
  key: (req) => req.headers.get('x-api-key') || 'anonymous',

  // Tiered rate limits
  tiers: {
    free: { limit: 100, window: '1h' },
    pro: { limit: 5000, window: '1h' },
    enterprise: { limit: Infinity }
  },
  tier: (req) => req.headers.get('x-tier') || 'free',

  // Custom 429 response
  response: {
    message: 'Too many requests',
    statusCode: 429
  },
  // Or function:
  response: (info) => ({
    error: 'RATE_LIMITED',
    retryIn: info.resetIn
  }),

  // Headers configuration
  headers: {
    standard: true,   // RateLimit-* headers
    legacy: true,     // X-RateLimit-* headers
    retryAfter: true  // Retry-After header on 429
  },

  // Store (default: bun:sqlite)
  store: sqliteStore({ path: './ratelimit.db' }),

  // Skip rate limiting
  skip: (req) => req.url.includes('/health'),

  // Error handling
  onStoreError: (error, req) => {
    console.error('Store error:', error)
    return 'allow' // or 'deny'
  }
}, handler)

Storage Backends

SQLite Store (Default)

Uses Bun's native bun:sqlite for maximum performance. Default store.

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

// Default - uses bun:sqlite with in-memory database
Bun.serve({
  fetch: hitlimit({}, handler)
})

// Custom path for persistence
import { sqliteStore } from '@joint-ops/hitlimit-bun'

Bun.serve({
  fetch: hitlimit({
    store: sqliteStore({ path: './ratelimit.db' })
  }, handler)
})

Memory Store

For simple use cases without persistence.

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

Bun.serve({
  fetch: hitlimit({
    store: memoryStore()
  }, handler)
})

Redis Store

For distributed systems and multi-server deployments.

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

Bun.serve({
  fetch: hitlimit({
    store: redisStore({ url: 'redis://localhost:6379' })
  }, handler)
})

Response Headers

Every response includes rate limit information:

RateLimit-Limit: 100
RateLimit-Remaining: 99
RateLimit-Reset: 1234567890
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1234567890

When rate limited (429 Too Many Requests):

Retry-After: 42

Default 429 Response

{
  "hitlimit": true,
  "message": "Whoa there! Rate limit exceeded.",
  "limit": 100,
  "remaining": 0,
  "resetIn": 42
}

Performance

hitlimit-bun is optimized for Bun's runtime with native performance:

Store Benchmarks (Bun 1.3)

| Store | Operations/sec | vs Node.js | |-------|----------------|------------| | Memory | 7,210,000+ | +130% faster | | bun:sqlite | 520,000+ | +10% faster 🔥 | | Redis | 6,900+ | +3% faster |

HTTP Throughput

| Framework | With hitlimit-bun | Overhead | |-----------|-------------------|----------| | Bun.serve | 105,000 req/s | 12% | | Elysia | 115,000 req/s | 11% |

Note: Benchmark results vary by hardware and environment. Run your own benchmarks to see results on your specific setup.

Why bun:sqlite is So Fast

Node.js (better-sqlite3)          Bun (bun:sqlite)
─────────────────────────         ─────────────────
JavaScript                        JavaScript
    ↓                                 ↓
  N-API                           Direct Call
    ↓                                 ↓
  C++ Binding                     Native SQLite
    ↓                             (No overhead!)
  SQLite

better-sqlite3 uses N-API bindings with C++ overhead. bun:sqlite calls SQLite directly from Bun's native layer.

git clone https://github.com/JointOps/hitlimit-monorepo
cd hitlimit-monorepo
bun install
bun run benchmark:bun

Elysia Plugin Options

import { Elysia } from 'elysia'
import { hitlimit } from '@joint-ops/hitlimit-bun/elysia'

new Elysia()
  .use(hitlimit({
    limit: 100,
    window: '1m',
    key: ({ request }) => request.headers.get('x-api-key') || 'anonymous',
    tiers: {
      free: { limit: 100, window: '1h' },
      pro: { limit: 5000, window: '1h' }
    },
    tier: ({ request }) => request.headers.get('x-tier') || 'free'
  }))
  .get('/', () => 'Hello!')
  .listen(3000)

Related Packages

Why Not Use Node.js Rate Limiters in Bun?

Node.js rate limiters like express-rate-limit use better-sqlite3 which relies on N-API bindings. In Bun, this adds overhead and loses the performance benefits of Bun's native runtime.

hitlimit-bun is built specifically for Bun:

  • Uses native bun:sqlite (2.7x faster than better-sqlite3)
  • No FFI overhead or Node.js polyfills
  • First-class Elysia framework support
  • Optimized for Bun.serve's request handling

License

MIT - Use freely in personal and commercial projects.

Keywords

bun rate limit, bun rate limiter, bun middleware, bun api, bun server, bun serve, bun framework, bun native, bun sqlite, elysia rate limit, elysia plugin, elysia middleware, elysia throttle, elysia framework, api rate limiting, throttle requests, request throttling, bun api protection, ddos protection, brute force protection, login protection, redis rate limit, high performance rate limit, fast rate limiter, sliding window, fixed window, rate-limiter-flexible bun, express-rate-limit bun, bun http, bun backend, bun rest api