valve_

Introduction

valve puts one rate limit in front of an API and shares it with every worker that calls that API.

Most providers enforce a quota per credential, not per process. When ten workers each run their own limiter, they spend the same quota ten times over and the provider starts returning 429 Too Many Requests. valve keeps the budget in Redis or Valkey, so every process that uses the same valve id draws from one shared limit. When the provider asks for a pause, every worker pauses.

import { createValve } from 'valvejs';
import { redisStore } from 'valvejs/redis';

const hubspot = createValve({
  id: 'hubspot:portal-123',
  rate: { limit: 190, interval: '10s' },
  store: redisStore({ client: redis }),
});

const limitedFetch = hubspot.wrapFetch();
const response = await limitedFetch(
  'https://api.hubapi.com/crm/v3/objects/contacts',
);

Beta until 1.0. APIs may change between releases. Install valvejs with plain version numbers through npm’s default channel.

What valve does

  • Shares a budget across processes. Atomic Lua scripts check and spend every rule in one round trip, on the store's clock.
  • Queues work locally. Jobs wait in-process with priorities, cost, concurrency limits, queue bounds, deadlines, and abort signals.
  • Listens to the provider. valve reads Retry-After, IETF RateLimit, and common x-ratelimit-* headers, then pauses every worker sharing the budget.
  • Retries rate limit responses for idempotent methods. wrapFetch retries a 429 after the shared pause ends, without losing its place in the queue.
  • Stays small. Zero runtime dependencies. ESM and CommonJS builds with full TypeScript declarations. Bring your own ioredis or node-redis client.

When to use it

You need toUse
Respect a provider quota shared by several processesvalve with the Redis store
Space calls from a single script or servicevalve with the default memory store
Limit parallel work inside one process, with no quotap-limit or p-queue
Accept or reject inbound requests to your own serverAn inbound rate limiter
Keep jobs across process restartsA durable job queue, with valve around outbound calls

valve limits when calls start. It does not persist queued jobs, retry arbitrary failures, or act as a circuit breaker.

Next steps

On this page