Products / SaaS / Backend Infrastructure
RateGuard
API rate limits in Postgres — fixed or sliding, by key or IP
Express middleware for fixed or sliding windows in Postgres, keyed by API key and/or IP, returning 429 + Retry-After and X-RateLimit-* headers.
Value
Problem. Public APIs get abused. Many rate-limit samples need Redis; in-memory limits fail across processes.
How it helps. Express middleware for fixed or sliding windows in Postgres, keyed by API key and/or IP, returning 429 + Retry-After and X-RateLimit-* headers.
Why buy. Postgres-backed rate limiting with hashed API keys and a smashable /v1/echo demo — own the code until Redis latency forces a swap.
- Fixed-window atomic counters and sliding-window event log
- Per-key limits + admin create/list/revoke behind ADMIN_TOKEN
- Standard 429, Retry-After, X-RateLimit-* headers
How it works
flowchart LR
Client -->|X-API-Key or IP| MW[RateGuard Middleware]
MW -->|resolve subject| Subject["key:id or ip:addr"]
MW -->|consume 1| Store[(Postgres)]
Store -->|fixed window| Buckets[rate_buckets]
Store -->|sliding window| Events[rate_events]
MW -->|under limit| Handler[/v1/echo/]
MW -->|over limit| R429["429 + Retry-After"]
Mermaid flowchart (render in GitHub / VS Code / mermaid.live).
Use case
Issue a demo key with max=5/min; smash /v1/echo — fifth request succeeds, sixth returns 429 with Retry-After.
What you get
- Rate limit middleware + memory store for tests
- Admin key CRUD + /v1/echo demo
- docker-compose.yml (host 5435)
- scripts/demo-curl.sh
- 17 Vitest tests
- MIT license
Project structure
rateguard/
src/
middleware/ rateLimit, adminAuth
stores/ fixedWindow, slidingWindow, memory
routes/ admin, echo, health
services/ apiKeys
prisma/ tests/ scripts/demo-curl.sh docker-compose.yml
Quick start
docker compose up -d
cp .env.example .env
npm install && npm run prisma:generate && npm run prisma:migrate
npm run dev
# POST /admin/keys then GET /v1/echo with X-API-Key
Example
From src/middleware/rateLimit.ts
// Resolve subject (api key id or IP) → store.consume(1)
// Under limit → set X-RateLimit-* and continue
// Over limit → 429 + Retry-After
Tested
17 Vitest tests — subject resolution, crypto hash, memory fixed/sliding consume, middleware under/over limit.
npm test
2026-09-20 — 17 passed; npm run build OK
Design decisions
- Store interface (consume) so Redis can replace Postgres later without rewriting middleware
- API secrets hashed at rest; raw secret shown once on create
- Default fixed window for simple atomic upserts; sliding optional
Limitations
- Not an API gateway / WAF / Kong replacement
- Single Postgres primary — multi-region needs a shared store or Redis swap
- Sliding window uses advisory locks per subject — fine for indie load, not infinite scale
- IP fallback trusts proxy headers only if you configure them correctly
Who it’s for
SaaS APIs that already use Postgres and need key/IP limits before abuse.
Not for: Teams standardized on Redis rate limiters or edge gateway products.
What you own
Full MIT-licensed TypeScript source via Gumroad ZIP. Fork it, ship it commercially, keep the license notice. You are responsible for secrets, hardening, and production ops.
Related
IdemKey · HookQueue · TenantScope · CronLock
Demo