A simple gateway. It's all you need.
Production-grade HTTP API gateway in pure TypeScript on native node:http —
zero runtime dependencies, one process, no frameworks.
npm · Documentation · Getting Started · Feature Matrix · Report a bug
Most gateways pull in a framework, a router, an HTTP client, a metrics
library, and a dozen transitive packages before they proxy a single byte.
This one doesn't. Every hot-path component — radix router, connection pool,
circuit breaker, cache, compression — is implemented on the Node.js standard
library, which means a trivial audit surface, no supply-chain churn, and a
node_modules you can read in one sitting.
npm install typescript-gateway → 0 production packages
node dist/index.js → that's the whole runtime
npm install typescript-gatewayOr globally, to get the tsgate CLI on your PATH:
npm install -g typescript-gatewaymkdir my-gateway && cd my-gateway
npm init -y
npm install typescript-gateway tsx
npx tsgate init .
npx tsgate start
curl http://localhost:8088/healthinit scaffolds a minimal config (gateway.config.json):
{
"server": { "port": 8088 },
"routes": [{ "method": "GET", "path": "/api/*" }],
"upstreams": [{ "id": "backend", "host": "localhost", "port": 3000 }]
}Every GET /api/** now proxies to localhost:3000 with connection pooling,
circuit breaking, and caching already on the hot path.
Use it as a library, no CLI required:
import { Gateway } from 'typescript-gateway';
const gateway = new Gateway('./gateway.config.json');
await gateway.start();Core routing — radix-tree router (O(log n) dynamic, O(1) static) · request-context pooling · streaming proxy path for large bodies · single-flight request coalescing (a cache-miss stampede costs one upstream call, not N) · client-disconnect propagation (abort upstream work when the caller goes away) · WebSocket tunneling (opt-in) · zero-dep OpenAPI 3 generator from the live route table
Resilience — circuit breaker (CLOSED/OPEN/HALF_OPEN) · retries with exponential backoff + jitter · active/passive/hybrid health checks · fallback handler with stale serving · hierarchical timeouts · per-route timeout override
Traffic control — rate limiting (token bucket, sliding window, fixed
window) · response cache with SWR, Vary-aware keys, and conditional
revalidation (ETag/Last-Modified persisted; upstream 304 merges without a
body transfer) · load balancing (round-robin, least-connections, weighted,
IP hash, random)
Payload — stream-based body parsing (JSON, URL-encoded, multipart, text) · request/response transformation · compression (gzip, brotli, deflate)
Identity & security — JWT auth · API keys · upstream credential injection (HMAC signing) · RFC 7807 problem details
Observability — lock-free metrics with histograms · structured logging · sampled access logging (errors ≥ 500 always logged) · live performance dashboard · CPU/memory profilers
Operations — validated config with env interpolation and hot reload · plugin chain with isolated async hooks · auto-tuner
Full details: Feature Matrix — 52 features across 7 groups.
Measured on a 4-core x86_64 reference box (Node 22) — your mileage will vary:
| Metric | Value |
|---|---|
| Raw forward hop | ~223 µs/op |
| Hot path (benchmark target path) | P99 5 ms, ~38k RPS |
| Full proxy pipeline | ~3.2k RPS @ 100 parallel connections |
| Production dependencies | 0 |
npm run benchmark # load test with P99/RPS verdicts
npm run benchmark:router # radix router micro-benchimport { Plugin } from 'typescript-gateway';
export const myPlugin: Plugin = {
name: 'my-plugin',
version: '1.0.0',
async preRoute(ctx) {
// before routing
},
async postResponse(ctx) {
// after the response is sent
},
};Lifecycle hooks: init · preRoute · preHandler · postHandler ·
postResponse · onError · destroy. Hooks listed in plugin.asyncHooks
run off the request path (setImmediate-scheduled) — latency-sensitive
plugins never block responses.
The docs ship inside the package, version-matched, so an agent reads the API it actually has instead of its training data:
node_modules/typescript-gateway/dist/docs/index.md
tsgate init writes AGENTS.md and CLAUDE.md (the latter imports the former
with @AGENTS.md); tsgate start re-upserts them. The rules live in a managed
<!-- BEGIN:tsgate-agent-rules --> block — anything you write outside it is
preserved.
npm run dev # tsx, hot reload
npm test # 1086 tests (vitest)
npm run typecheck # strict tsc, zero errors
npm run build # compile to dist/
npm run benchmark # load-test with pass/fail verdicts
npm run site:dev # docs site (Astro) locallysrc/
├── core/ router, server, proxy handler, pools, cache, breaker
├── pipeline/ policy chain (rate limit, cache, auth, …)
├── plugins/ plugin loader + execution chain
├── config/ schema, loader, validator, hot reload
└── types/ shared contracts
site/ docs site → tsgate.diama.dev
benchmarks/ load + micro benchmarks
tests/ unit, integration, performance
- Node.js ≥ 20
- That's it.
Contributions are welcome — see CONTRIBUTING.md for the dev setup, the test/TDD workflow, and the commit convention. Performance- critical changes must ship with a benchmark. New features need unit tests; the suite is the contract.
This project follows the Contributor Covenant. To report a security issue, see SECURITY.md.