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

@nexpress/rate-limiter-redis

v0.3.8

Published

Redis-backed NpRateLimiterAdapter for multi-node NexPress deploys.

Readme

@nexpress/rate-limiter-redis

Redis-backed NpRateLimiterAdapter for multi-node NexPress deployments.

The default InMemoryRateLimiter shipped in @nexpress/core keeps per-IP buckets in a process-local Map, which means the effective limit on a 4-node cluster is 4 × configured. Swap in this adapter at boot to share the bucket across every instance.

Install

pnpm add @nexpress/rate-limiter-redis

ioredis is bundled as a regular dependency — there's no peer contract to satisfy.

Usage

// apps/web/src/lib/init-core.ts (or your app's bootstrap)
import { setRateLimiter } from "@nexpress/core/rate-limit";
import { RedisRateLimiter } from "@nexpress/rate-limiter-redis";

setRateLimiter(new RedisRateLimiter({ url: process.env.NP_REDIS_URL }));

Three constructor shapes:

// 1. Connection string (most common).
new RedisRateLimiter({ url: "redis://localhost:6379" });

// 2. ioredis options (host/port/password/cluster/etc.).
new RedisRateLimiter({ host: "redis.internal", port: 6379, db: 1 });

// 3. Reuse an existing ioredis client (e.g. shared with caching).
//    The adapter does NOT close the client on shutdown() in this
//    mode — the caller owns the lifecycle.
const client = new Redis(process.env.NP_REDIS_URL);
new RedisRateLimiter({ client });

Optional keyPrefix (defaults to "nx:rl:") lets two NexPress deploys share a Redis without colliding:

new RedisRateLimiter({ url, keyPrefix: "myapp:rl:" });

How it works

A single Lua script issues INCR + PTTL + a conditional PEXPIRE in one round trip per request. That gives:

  • Atomicity — no race where two concurrent requests both see count <= limit because the increment happens server-side.
  • TTL safety — a crash between INCR and EXPIRE in a naive two-step implementation would strand a key without a TTL. The Lua script sets the TTL inside the same call so the bucket always expires.
  • One round trip per check — the proxy's hot path stays cheap.

Sliding-window or token-bucket semantics are out of scope for v0.1; the adapter implements the same fixed-window contract as InMemoryRateLimiter so behavior is identical to single-node deploys.

Shutdown

Call await limiter.shutdown() from your process's SIGTERM handler if the adapter owns its client (cases 1 and 2 above). It's a no-op when you passed in a shared client.

Tests

The unit suite stubs ioredis. To run the optional live Redis integration test:

docker compose -f docker/docker-compose.yml --profile redis up -d redis
TEST_REDIS_URL=redis://localhost:6379 pnpm --filter @nexpress/rate-limiter-redis test

When TEST_REDIS_URL is unset, the live integration test is skipped.

License

MIT