Why Rezo
Most HTTP libraries solve one problem well and leave you to piece together the rest. Rezo ships everything a production HTTP client needs in a single package: cookie management, proxy rotation, browser stealth, web crawling, staged timeouts, response caching, request queuing, and full site cloning. It runs on every JavaScript runtime without changing a line of code.
One Client, Every Runtime
Rezo runs on Node.js, Bun, Deno, browsers, React Native, and edge runtimes like Cloudflare Workers. Your application code stays identical — Rezo automatically selects the right adapter for the environment.
// This code runs everywhere -- no conditional imports, no polyfills
import rezo from 'rezo';
// Callable like fetch()
const { data } = await rezo('https://api.example.com/users');
// Or use named methods
const { data: users } = await rezo.get('https://api.example.com/users'); Six Adapters, Auto-Selected
Rezo ships with six adapters, each optimized for a specific runtime:
| Adapter | Runtime | Best For |
|---|---|---|
| HTTP | Node.js, Bun | Server-side requests with full control |
| HTTP/2 | Node.js, Bun | Multiplexed connections, server push |
| cURL | Node.js | TLS fingerprint impersonation, debugging |
| Fetch | Browsers, Deno, Bun, Edge | Universal compatibility |
| XHR | Browsers | Upload progress events, legacy support |
| React Native | React Native, Expo | Mobile HTTP with native bridge |
The adapter picker detects your environment at import time and selects the best option. You can also set an adapter explicitly per-instance or per-request.
Built-In Cookie Jar
Every Rezo instance carries a cookie jar. Cookies are captured from Set-Cookie headers, stored per domain and path, and sent back automatically on subsequent requests. No third-party plugins required.
import { Rezo, CookieJar } from 'rezo';
const jar = new CookieJar();
const client = rezo.create({ jar });
// Login -- cookies are captured automatically
await client.postJson('https://example.com/login', { user: 'ada', pass: 'secret' });
// Authenticated request -- cookies are sent automatically
const { data } = await client.get('https://example.com/dashboard');
// Export cookies for persistence
const json = jar.toJSON(); // JSON format
const netscape = jar.toNetscape(); // Netscape/cURL format Proxy Rotation with Health Monitoring
Rezo’s ProxyManager rotates through a pool of proxies with health tracking, automatic failover, and support for HTTP, HTTPS, SOCKS4, and SOCKS5 protocols.
import { Rezo, ProxyManager } from 'rezo';
const proxies = new ProxyManager([
'http://proxy1.example.com:8080',
'socks5://proxy2.example.com:1080',
'https://user:pass@proxy3.example.com:3128',
]);
const client = rezo.create({ proxyManager: proxies });
// Each request uses the next healthy proxy
await client.get('https://target.com/page1');
await client.get('https://target.com/page2'); 18 Browser Stealth Profiles
The stealth module makes requests indistinguishable from real browser traffic. It controls TLS fingerprints, HTTP/2 SETTINGS frames, header ordering, client hints, and navigator properties.
import rezo from 'rezo';
import { RezoStealth } from 'rezo/stealth';
const stealth = new RezoStealth('chrome-131');
const client = rezo.create({ stealth });
// Request looks identical to Chrome 131 on the wire
const { data } = await client.get('https://protected-site.com'); 18 profiles across Chrome, Firefox, Safari, Edge, Opera, and Brave. Use rotate: true for a fresh identity on every request.
Web Crawler with SQLite Persistence
Rezo includes a production-grade web crawler with queue-based URL processing, robots.txt compliance, memory monitoring, and resumable sessions backed by SQLite.
import { Crawler } from 'rezo/crawler';
const crawler = new Crawler({
startUrls: ['https://example.com'],
maxDepth: 3,
concurrency: 10,
respectRobotsTxt: true,
});
for await (const result of crawler) {
console.log(result.url, result.status);
} 26 Lifecycle Hooks
Hooks let you intercept every phase of the HTTP lifecycle: DNS resolution, TCP connect, TLS handshake, redirect, retry, cookie processing, and more. Each hook point accepts an array of handlers.
const client = rezo.create({
hooks: {
beforeRequest: [(config) => { config.headers.set('X-Trace', uuid()); }],
afterResponse: [(response) => { log(response.timing); return response; }],
beforeRetry: [(config, error, context) => { refreshToken(config); }],
}
}); Staged Timeouts
Instead of a single timeout, Rezo provides granular control over each phase of a request:
const client = rezo.create({
timeout: {
connect: 5_000, // TCP connection
headers: 10_000, // Time to first byte
body: 30_000, // Full body download
total: 60_000, // Overall request limit
}
}); Response and DNS Caching
Cache responses in memory or with a custom store. DNS results are cached to eliminate redundant lookups.
const client = rezo.create({
cache: { ttl: 60_000, maxSize: 100 },
dnsCache: { ttl: 300_000 },
});
// First request hits the server
await client.get('https://api.example.com/config');
// Second request served from cache
await client.get('https://api.example.com/config'); Request Queue with Per-Domain Concurrency
The built-in request queue prevents overwhelming servers with configurable concurrency and rate limiting.
const client = rezo.create({
queueOptions: {
enable: true,
options: {
concurrency: 5,
interval: 1000,
intervalCap: 2,
}
}
}); Full Site Cloning
The wget module mirrors entire websites to disk, converting links for offline browsing.
import { Wget } from 'rezo/wget';
const wget = new Wget({
url: 'https://docs.example.com',
outputDir: './mirror',
depth: 5,
convertLinks: true,
});
await wget.run(); 70+ Structured Error Codes
Every error carries a machine-readable code, boolean classification flags, and a recovery suggestion. No more guessing what went wrong.
import rezo, { RezoError } from 'rezo';
try {
await rezo.get('https://api.example.com/data');
} catch (error) {
if (rezo.isRezoError(error)) {
console.log(error.code); // "REZ_TIMEOUT"
console.log(error.isTimeout); // true
console.log(error.suggestion); // "Increase the timeout or check server health"
}
} TypeScript-First
Rezo is written in strict TypeScript from the ground up. Every method, option, and response is fully typed with generics, overloads, and discriminated unions.
interface User {
id: number;
name: string;
}
// data is typed as User[]
const { data } = await rezo.get<User[]>('/api/users');
// Full IDE autocomplete on config
await rezo.get('/api/users', {
params: { page: 1 },
timeout: { total: 5000 },
retry: { limit: 3 },
}); Feature Comparison
How Rezo compares to other popular HTTP libraries:
| Feature | Rezo | Axios | Got | node-fetch | Undici | superagent |
|---|---|---|---|---|---|---|
| TypeScript-native | ● | ● | ● | ○ | ● | ○ |
| Node.js | ● | ● | ● | ● | ● | ● |
| Browsers | ● | ● | ○ | ○ | ○ | ● |
| Deno / Edge | ● | ● | ○ | ○ | ○ | ○ |
| React Native | ● | ◑ | ○ | ○ | ○ | ◑ |
| HTTP/2 | ● | ○ | ● | ○ | ● | ○ |
| Cookie jar | ● Built-in | ◑ Plugin | ◑ Plugin | ○ | ○ | ◑ Plugin |
| Cookie persistence | ● Built-in | ○ | ○ | ○ | ○ | ○ |
| Proxy rotation | ● Built-in | ○ | ○ | ○ | ○ | ○ |
| SOCKS proxy | ● Built-in | ◑ Plugin | ○ | ○ | ○ | ○ |
| Stealth / TLS fingerprint | ● Built-in | ○ | ○ | ○ | ○ | ○ |
| Web crawler | ● Built-in | ○ | ○ | ○ | ○ | ○ |
| Lifecycle hooks | ● 26 hooks | ◑ 2 | ◑ 9 | ○ | ○ | ○ |
| Staged timeouts | ● 4 phases | ◑ Single | ◑ Partial | ○ | ◑ Single | ○ |
| Response caching | ● Built-in | ○ | ◑ Plugin | ○ | ○ | ○ |
| DNS caching | ● Built-in | ○ | ◑ Plugin | ○ | ○ | ○ |
| Request queue | ● Built-in | ○ | ○ | ○ | ○ | ○ |
| Site cloning (wget) | ● Built-in | ○ | ○ | ○ | ○ | ○ |
| cURL adapter | ● | ○ | ○ | ○ | ○ | ○ |
| Downloads + progress | ● Built-in | ◑ Partial | ● | ○ | ○ | ◑ Partial |
| Uploads + progress | ● Built-in | ● | ○ | ○ | ○ | ◑ Partial |
| Retry with backoff | ● Built-in | ◑ Plugin | ● | ○ | ● | ◑ Plugin |
| Structured error codes | ● 70+ | ◑ 6 | ◑ ~12 | ○ | ◑ ~10 | ○ |
| Recovery suggestions | ● | ○ | ○ | ○ | ○ | ○ |
Next Steps
Ready to switch? Pick the guide that matches your current library:
- From Axios — Familiar API, painless migration
- From node-fetch — Upgrade from manual everything
- From Got — Feature-rich to feature-complete
- From Fetch API — Full power on top of native fetch
- From Undici — Keep the performance, gain the features
- From superagent — Modernize your HTTP stack