Edge & Runtime Support
The TypeScript SDK's core is edge-safe zero Node built-ins. Run the limiter on Cloudflare Workers, Deno, Bun, and Vercel Edge alongside Node.
Edge-safe core
Limiter, algorithms, InMemoryStore, extractors, presets, OTel adapter all use zero Node built-ins.
RedisStore is Node-only
ioredis needs TCP. For edge distributed limits, inject a fetch-based REST client satisfying RedisClientLike.
Dual ESM + CJS
Both module formats with per-condition type declarations across every adapter entrypoint.
What works where
| Runtime | Limiter core | InMemoryStore | RedisStore |
|---|---|---|---|
| Node.js | ✓ | ✓ | ✓ |
| Bun | ✓ | ✓ | ✓ |
| Deno | ✓ | ✓ | |
| Cloudflare Workers | ✓ | ✓ | |
| Vercel Edge | ✓ | ✓ |
Distributed limits on the edge
The packaged RedisStore talks to ioredis over TCP, which isn't available on most edge runtimes. The store is decoupled from the client through the RedisClientLike interface pass any object that satisfies it and the Lua scripts run unchanged. The easiest path on Cloudflare Workers and Vercel Edge is the Upstash REST client:
npm install @upstash/redisimport { Redis } from '@upstash/redis';
import { RateLimiter, RedisStore, presets } from 'halt-rate';
// Upstash exposes a fetch-based client that's safe on edge runtimes.
const upstash = Redis.fromEnv();
// A thin adapter satisfying RedisClientLike (eval / get / set / etc).
const client = {
eval: (script: string, keys: string[], args: (string | number)[]) =>
upstash.eval(script, keys, args),
// …add the few other methods RedisClientLike needs for your algorithms
};
const store = new RedisStore({ client });
const limiter = new RateLimiter({ store, policy: presets.PUBLIC_API });See RedisStore docs for the full interface shape, fail-open behaviour, and metrics.
Hono on Cloudflare Workers
The new Hono adapter derives the client IP from edge headers (x-forwarded-for / cf-connecting-ip / x-real-ip) out of the box. Override with getClientIp for custom edge proxies.
import { Hono } from 'hono';
import { RateLimiter, InMemoryStore, presets } from 'halt-rate';
import { haltMiddleware } from 'halt-rate/hono';
const limiter = new RateLimiter({ store: new InMemoryStore(), policy: presets.PUBLIC_API });
const app = new Hono();
app.use('*', haltMiddleware({ limiter }));
export default app;ESM + CJS
The package ships dual builds with proper exports conditions and types per entrypoint halt-rate, halt-rate/express, halt-rate/next, halt-rate/hono, halt-rate/fastify, and halt-rate/graphql all resolve in both ESM and CommonJS projects with no extra config.